Skip to content

feature/identifiers #208

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 15, 2025
Merged

feature/identifiers #208

merged 3 commits into from
Apr 15, 2025

Conversation

nanotaboada
Copy link
Owner

@nanotaboada nanotaboada commented Apr 15, 2025

Summary by CodeRabbit

  • New Features

    • Added a script to automate database migrations and copying of the SQLite database file.
    • Introduced initial data seeding for players via a new migration.
  • Bug Fixes

    • Enforced unique squad numbers for players to prevent duplicates.
  • Refactor

    • Changed player identification from numeric IDs to GUIDs and/or squad numbers across the API.
    • Updated controller endpoints, services, data models, and tests to use squad number or GUID as the key.
    • Made several player fields optional and ensured squad number uniqueness at the database level.
  • Chores

    • Updated configuration to exclude scripts from static analysis and code coverage.
    • Improved project file handling for the database file.
    • Removed unused utilities and legacy seeding logic.
  • Tests

    • Updated and expanded unit tests to reflect changes in player identification and data seeding.

Copy link

coderabbitai bot commented Apr 15, 2025

Walkthrough

This change refactors the Player entity and related application logic to use a Guid as the internal primary key (Id) and shifts all public-facing operations to use SquadNumber as the main identifier. Entity Framework Core configurations, migrations, repository and service interfaces, controllers, validators, and all related tests are updated to reflect this new key structure. Additionally, the project removes custom async seeding utilities in favor of EF Core migrations, introduces a new migration to seed initial player data, and updates configuration files to exclude scripts from analysis and coverage. Supporting scripts and project files are also updated accordingly.

Changes

File(s) / Path(s) Change Summary
.codacy.yml, codecov.yml Updated static analysis and code coverage configs to exclude the scripts directory.
scripts/run-migrations-and-copy-database.sh Added a new Bash script to automate EF Core migrations and database file management.
src/Dotnet.Samples.AspNetCore.WebApi/Controllers/PlayerController.cs Refactored controller to use SquadNumber as the main identifier for player operations; restricted Id-based GET to Admins and made it hidden.
src/Dotnet.Samples.AspNetCore.WebApi/Data/IPlayerRepository.cs,
src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerRepository.cs
Changed FindBySquadNumberAsync to return Task<Player?>; added SquadNumberExistsAsync for uniqueness checks.
src/Dotnet.Samples.AspNetCore.WebApi/Data/IRepository.cs,
src/Dotnet.Samples.AspNetCore.WebApi/Data/Repository.cs
Changed entity identifier parameters from long to Guid in repository interfaces and implementations.
src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerDbContext.cs Added explicit model configuration: primary key as Guid, unique index on SquadNumber.
src/Dotnet.Samples.AspNetCore.WebApi/Dotnet.Samples.AspNetCore.WebApi.csproj Only includes the SQLite database file if it exists.
src/Dotnet.Samples.AspNetCore.WebApi/Migrations/* Updated/added migrations to use Guid for Id, make certain fields nullable, and add a unique index on SquadNumber; added seeding migration.
src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs Changed Id property from long to Guid with default initialization.
src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerRequestModel.cs,
src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerResponseModel.cs
Removed the Id property from request and response models.
src/Dotnet.Samples.AspNetCore.WebApi/Program.cs Removed async seeding utility and its usage; cleaned up imports.
src/Dotnet.Samples.AspNetCore.WebApi/Services/IPlayerService.cs,
src/Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs
Changed method signatures to use Guid for Id and int for SquadNumber as appropriate; updated logic for update/delete by squad number.
src/Dotnet.Samples.AspNetCore.WebApi/Validators/PlayerRequestModelValidator.cs Injected IPlayerRepository and added async uniqueness validation for SquadNumber.
src/Dotnet.Samples.AspNetCore.WebApi/Utilities/ApplicationBuilderExtensions.cs,
src/Dotnet.Samples.AspNetCore.WebApi/Utilities/DbContextUtils.cs
Removed custom database seeding utilities.
src/Dotnet.Samples.AspNetCore.WebApi/Utilities/PlayerData.cs Changed namespace, removed explicit Id assignments, added method to create player data with GUIDs, and updated JSON data accordingly.
test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs,
test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs
Updated tests to use Guid for Id and int for SquadNumber; changed test logic to match new key usage.
test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs Updated all player fakes to use Guid for Id and SquadNumber for lookups; removed Id from models and methods.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller
    participant Service
    participant Repository
    participant DbContext

    %% Example: Creating a Player (POST)
    Client->>Controller: POST /players (PlayerRequestModel)
    Controller->>Service: RetrieveBySquadNumberAsync(squadNumber)
    Service->>Repository: FindBySquadNumberAsync(squadNumber)
    Repository->>DbContext: Query Player by SquadNumber
    DbContext-->>Repository: Player/null
    Repository-->>Service: Player/null
    Service-->>Controller: Player/null
    alt Player exists
        Controller-->>Client: 409 Conflict
    else Player does not exist
        Controller->>Service: CreateAsync(PlayerRequestModel)
        Service->>Repository: AddAsync(Player)
        Repository->>DbContext: Add Player
        DbContext-->>Repository: Success
        Repository-->>Service: Player
        Service-->>Controller: PlayerResponseModel
        Controller-->>Client: 201 Created (Location: /players/squadNumber/{squadNumber})
    end

    %% Example: GET by Id (Admin only)
    Client->>Controller: GET /players/{id}
    Controller->>Service: RetrieveByIdAsync(Guid id)
    Service->>Repository: FindByIdAsync(Guid id)
    Repository->>DbContext: Query Player by Id
    DbContext-->>Repository: Player/null
    Repository-->>Service: Player/null
    Service-->>Controller: PlayerResponseModel/null
    Controller-->>Client: 200 OK / 404 Not Found
Loading

Possibly related issues

Possibly related PRs

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-advanced-security
Copy link

This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation.

Copy link

codacy-production bot commented Apr 15, 2025

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
-3.89% 8.49%
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (82a9fcf) 799 186 23.28%
Head commit (fa6abd1) 1011 (+212) 196 (+10) 19.39% (-3.89%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#208) 318 27 8.49%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

Copy link

codecov bot commented Apr 15, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 100.00%. Comparing base (82a9fcf) to head (fa6abd1).
Report is 4 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##            master      #208   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            2         2           
  Lines          173       183   +10     
  Branches        14        14           
=========================================
+ Hits           173       183   +10     
Components Coverage Δ
Controllers 100.00% <100.00%> (ø)
Services 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (14)
src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs (1)

13-13: Good use of Guid with default initialization

Changing the Id property from long to Guid with default initialization is appropriate for globally unique identifiers. This aligns well with the refactoring goal of using SquadNumber as the primary public identifier while maintaining a unique internal ID.

Consider documenting the property with XML comments to explain its role as an internal identifier versus the public-facing SquadNumber.

+    /// <summary>
+    /// Internal unique identifier for the player.
+    /// </summary>
+    /// <remarks>
+    /// This is used as the primary key in the database but not exposed through the API.
+    /// Public-facing operations use SquadNumber as the identifier.
+    /// </remarks>
     public Guid Id { get; set; } = Guid.NewGuid();
src/Dotnet.Samples.AspNetCore.WebApi/Program.cs (1)

90-90: Consider adding error handling around initialization.

The explicit initialization with await app.InitData() replaces the previous implicit EF Core seeding mechanism, which aligns with the identifier refactoring. However, consider adding error handling to gracefully handle initialization failures.

-await app.InitData();
+try
+{
+    // Initialize database with migrations and seed data
+    await app.InitData();
+}
+catch (Exception ex)
+{
+    Log.Logger.Error(ex, "An error occurred while initializing the database");
+    // Consider whether to continue or terminate based on your application requirements
+}
src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerRepository.cs (1)

13-16: Consider using _dbSet instead of direct dbContext access

For consistency with other repository methods, consider using the protected _dbSet field instead of directly accessing dbContext.Players. This ensures that if the repository is subclassed or the DbSet is overridden, the correct DbSet is always used.

public async Task<bool> SquadNumberExistsAsync(int squadNumber)
{
-    return await dbContext.Players.AnyAsync(p => p.SquadNumber == squadNumber);
+    return await _dbSet.AnyAsync(p => p.SquadNumber == squadNumber);
}
src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerData.cs (1)

156-312: Well-implemented method for internal GUID-based identification.

The new MakeStarting11WithId() method properly supports the refactoring to use GUIDs for internal identification while maintaining all player properties. The use of explicit GUIDs ensures deterministic seeding for consistent test environments and data migrations.

However, there's significant code duplication between this method and both MakeStarting11() and the test utilities in PlayerFakes.cs.

Consider refactoring to use a single source of player data with a factory method that optionally adds IDs:

+ private static readonly List<PlayerData> _playerBaseData = new()
+ {
+     new() { FirstName = "Damián", MiddleName = "Emiliano", LastName = "Martínez", ... },
+     // ... other players
+ };
+
+ public static List<Player> MakeStarting11(bool includeIds = false)
+ {
+     return _playerBaseData.Select(p => new Player
+     {
+         Id = includeIds ? Guid.Parse(p.IdString) : Guid.NewGuid(),
+         FirstName = p.FirstName,
+         // ... other properties
+     }).ToList();
+ }
+
+ public static List<Player> MakeStarting11WithId() => MakeStarting11(true);
🧰 Tools
🪛 GitHub Check: Codeac Code Quality

[warning] 203-218: CodeDuplication
This block of 15 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:62


[warning] 217-232: CodeDuplication
This block of 15 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:76


[warning] 231-246: CodeDuplication
This block of 15 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:90


[warning] 245-260: CodeDuplication
This block of 15 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:104


[warning] 259-274: CodeDuplication
This block of 15 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:118

src/Dotnet.Samples.AspNetCore.WebApi/Utilities/DbContextUtils.cs (1)

7-14:

❓ Verification inconclusive

Simplified synchronous database seeding.

The seeding method has been changed from asynchronous to synchronous, which simplifies the initialization process but may impact performance for larger datasets. However, for the current data size, this should not be an issue.

Note that the method now uses MakeStarting11() rather than MakeStarting11WithId(), which means that GUIDs will be automatically generated rather than using the predefined GUIDs from the new method. This could lead to inconsistency between development and test environments.

Consider whether you should be using MakeStarting11WithId() for seeding to ensure consistent GUIDs across environments:

- context.Players.AddRange(PlayerData.MakeStarting11());
+ context.Players.AddRange(PlayerData.MakeStarting11WithId());

Run this script to verify which method is used for seeding in the migrations:


🏁 Script executed:

#!/bin/bash
# Check which seeding method is used in the migrations
rg -A 5 "MakeStarting11" --glob "**Migrations/*.cs"

Length of output: 200


Review Comment Update: Verify GUID Consistency in Database Seeding

Although the change to synchronous seeding simplifies initialization, our automated search for migration files referencing the seeding methods (using rg with a glob filter for “Migrations/*.cs”) did not return any files. This means we couldn’t confirm whether migrations rely on a different seeding approach. Please verify manually whether any migration code (or other parts of the repository) uses seeding logic that expects consistent GUIDs generated by MakeStarting11WithId() rather than MakeStarting11(). If consistency across development and test environments is required, update the seeding call accordingly:

- context.Players.AddRange(PlayerData.MakeStarting11());
+ context.Players.AddRange(PlayerData.MakeStarting11WithId());

Ensure that any discrepancy between environments is intentional.

src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414195445_SeedStarting11.cs (1)

16-49: Insert data in batches (optional).
Inserting each row in a loop is valid but may be slower against certain database providers. Consider one of these approaches if performance or cleanliness is a concern:

  1. Batch insertion of multiple rows with a single InsertData call.
  2. Using reflection-based seeding if code duplication is high.
scripts/run-migrations-and-copy-database.sh (3)

20-24: Tool availability check is good.
Your check for dotnet ef ensures a smooth script flow. Optionally, consider adding set -e or set -eo pipefail at the top to fail fast on errors without manually checking $? after each command.


34-37: Check exit code directly in the migration step.
Instead of using $?, consider using a direct check; for example:

-dotnet ef database update --project "$PROJECT_ROOT_PATH"
-if [ $? -ne 0 ]; then
+if ! dotnet ef database update --project "$PROJECT_ROOT_PATH"; then
    log "❌" "ERROR" "Migration failed. See error above."
    exit 1
fi

This aligns with shell best practices and avoids potential race conditions.

🧰 Tools
🪛 GitHub Check: CodeFactor

[notice] 34-34: scripts/run-migrations-and-copy-database.sh#L34
Check exit code directly with e.g. 'if ! mycmd;', not indirectly with $?. (SC2181)


45-47: Check copy operation directly.
Similar to the EF command, checking $? can be replaced by a direct conditional on the cp command:

-cp -f "$SOURCE_FILE_PATH" "$TARGET_FILE_PATH"
-if [ $? -eq 0 ]; then
+if cp -f "$SOURCE_FILE_PATH" "$TARGET_FILE_PATH"; then
    log "✅" "INFO" "Database successfully copied to '$TARGET_FILE_PATH'"
else
🧰 Tools
🪛 GitHub Check: CodeFactor

[notice] 45-45: scripts/run-migrations-and-copy-database.sh#L45
Check exit code directly with e.g. 'if mycmd;', not indirectly with $?. (SC2181)

src/Dotnet.Samples.AspNetCore.WebApi/Validators/PlayerRequestModelValidator.cs (2)

33-36: Remove the redundant semicolon.

The trailing semicolon at line 36 constitutes an empty statement (SA1106). It's unnecessary and should be removed to clean up the fluent interface chain.

-            .WithMessage("SquadNumber must be unique.");
-        ;
+            .WithMessage("SquadNumber must be unique.");
🧰 Tools
🪛 GitHub Check: CodeFactor

[notice] 36-36: src/Dotnet.Samples.AspNetCore.WebApi/Validators/PlayerRequestModelValidator.cs#L36
Code should not contain empty statements. (SA1106)


45-48: Use or remove the cancellation token consistently.

Although the method signature includes a CancellationToken, it is not passed to _playerRepository.FindBySquadNumberAsync(squadNumber). If cancellation support is desired, update the repository method accordingly; otherwise, remove the token from this method to avoid confusion.

src/Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (1)

131-139: Clarify the log message.

The log message uses "Id" but refers to the squad number. Update it to avoid confusion for maintainers and operations staff reviewing logs.

-            "Player with Id {SquadNumber} removed from Repository",
+            "Removed player with SquadNumber {SquadNumber} from Repository",
src/Dotnet.Samples.AspNetCore.WebApi/Utilities/ApplicationBuilderExtensions.cs (2)

13-15: Align documentation with actual migration behavior.

The comments at lines 13–15 state that migrations are not applied, yet the method explicitly calls dbContext.Database.MigrateAsync(). Update the documentation so it reflects the true functionality.


29-32: Consider an async seed method.

DbContextUtils.Seed is synchronous, which can block the thread if seeding becomes heavier. If you anticipate more resource-intensive seeding, provide an asynchronous method for consistency with MigrateAsync.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 82a9fcf and 58a115f.

⛔ Files ignored due to path filters (1)
  • src/Dotnet.Samples.AspNetCore.WebApi/Data/players-sqlite3.db is excluded by !**/*.db
📒 Files selected for processing (28)
  • .codacy.yml (1 hunks)
  • codecov.yml (1 hunks)
  • scripts/run-migrations-and-copy-database.sh (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Controllers/PlayerController.cs (10 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Data/IPlayerRepository.cs (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Data/IRepository.cs (2 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerData.cs (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerDbContext.cs (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerRepository.cs (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Data/Repository.cs (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Dotnet.Samples.AspNetCore.WebApi.csproj (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414191223_InitialCreate.Designer.cs (2 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414191223_InitialCreate.cs (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414195445_SeedStarting11.Designer.cs (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414195445_SeedStarting11.cs (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Migrations/PlayerDbContextModelSnapshot.cs (2 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerRequestModel.cs (0 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerResponseModel.cs (0 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Program.cs (2 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Services/IPlayerService.cs (2 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (3 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Utilities/ApplicationBuilderExtensions.cs (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Utilities/DbContextUtils.cs (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Validators/PlayerRequestModelValidator.cs (3 hunks)
  • test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs (18 hunks)
  • test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs (9 hunks)
  • test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs (15 hunks)
💤 Files with no reviewable changes (2)
  • src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerResponseModel.cs
  • src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerRequestModel.cs
🧰 Additional context used
🧬 Code Graph Analysis (12)
src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414191223_InitialCreate.cs (1)
src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414195445_SeedStarting11.cs (1)
  • Down (53-60)
src/Dotnet.Samples.AspNetCore.WebApi/Data/IPlayerRepository.cs (1)
src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs (1)
  • Player (11-34)
src/Dotnet.Samples.AspNetCore.WebApi/Services/IPlayerService.cs (5)
src/Dotnet.Samples.AspNetCore.WebApi/Data/IPlayerRepository.cs (1)
  • Task (20-20)
src/Dotnet.Samples.AspNetCore.WebApi/Data/IRepository.cs (4)
  • Task (15-15)
  • Task (22-22)
  • Task (39-39)
  • Task (46-46)
src/Dotnet.Samples.AspNetCore.WebApi/Data/Repository.cs (4)
  • Task (10-14)
  • Task (16-16)
  • Task (20-24)
  • Task (26-34)
src/Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (4)
  • Task (48-56)
  • Task (62-91)
  • Task (93-97)
  • Task (99-103)
src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerResponseModel.cs (1)
  • PlayerResponseModel (11-26)
src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414191223_InitialCreate.Designer.cs (2)
src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414191223_InitialCreate.cs (1)
  • InitialCreate (9-48)
src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414195445_SeedStarting11.Designer.cs (1)
  • BuildTargetModel (18-67)
src/Dotnet.Samples.AspNetCore.WebApi/Validators/PlayerRequestModelValidator.cs (3)
src/Dotnet.Samples.AspNetCore.WebApi/Enums/Position.cs (5)
  • Position (3-63)
  • Position (19-20)
  • Position (33-34)
  • Position (47-48)
  • IsValidAbbr (61-62)
src/Dotnet.Samples.AspNetCore.WebApi/Data/IPlayerRepository.cs (1)
  • Task (20-20)
src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerRepository.cs (2)
  • Task (10-11)
  • Task (13-16)
src/Dotnet.Samples.AspNetCore.WebApi/Utilities/ApplicationBuilderExtensions.cs (3)
src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerDbContext.cs (1)
  • PlayerDbContext (10-38)
test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/DatabaseFakes.cs (2)
  • PlayerDbContext (29-34)
  • Seed (49-53)
src/Dotnet.Samples.AspNetCore.WebApi/Utilities/DbContextUtils.cs (2)
  • DbContextUtils (5-15)
  • Seed (7-14)
src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerData.cs (3)
src/Dotnet.Samples.AspNetCore.WebApi/Enums/Position.cs (4)
  • Position (3-63)
  • Position (19-20)
  • Position (33-34)
  • Position (47-48)
test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs (4)
  • List (15-171)
  • List (285-299)
  • Player (173-182)
  • Player (184-199)
src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs (1)
  • Player (11-34)
src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414195445_SeedStarting11.cs (2)
src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414191223_InitialCreate.cs (2)
  • Up (12-40)
  • Down (43-47)
src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerData.cs (1)
  • PlayerData (7-471)
src/Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (6)
src/Dotnet.Samples.AspNetCore.WebApi/Data/IPlayerRepository.cs (1)
  • Task (20-20)
src/Dotnet.Samples.AspNetCore.WebApi/Data/IRepository.cs (4)
  • Task (15-15)
  • Task (22-22)
  • Task (39-39)
  • Task (46-46)
src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerRepository.cs (2)
  • Task (10-11)
  • Task (13-16)
src/Dotnet.Samples.AspNetCore.WebApi/Data/Repository.cs (4)
  • Task (10-14)
  • Task (16-16)
  • Task (20-24)
  • Task (26-34)
src/Dotnet.Samples.AspNetCore.WebApi/Services/IPlayerService.cs (5)
  • Task (16-16)
  • Task (23-23)
  • Task (33-33)
  • Task (43-43)
  • Task (50-50)
src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs (1)
  • Player (11-34)
test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs (3)
src/Dotnet.Samples.AspNetCore.WebApi/Models/Player.cs (1)
  • Player (11-34)
src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerRequestModel.cs (1)
  • PlayerRequestModel (13-30)
src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerResponseModel.cs (1)
  • PlayerResponseModel (11-26)
src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414195445_SeedStarting11.Designer.cs (4)
src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414191223_InitialCreate.Designer.cs (2)
  • DbContext (13-68)
  • BuildTargetModel (18-67)
src/Dotnet.Samples.AspNetCore.WebApi/Migrations/PlayerDbContextModelSnapshot.cs (1)
  • DbContext (12-65)
src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerDbContext.cs (1)
  • PlayerDbContext (10-38)
src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414195445_SeedStarting11.cs (1)
  • SeedStarting11 (9-61)
src/Dotnet.Samples.AspNetCore.WebApi/Controllers/PlayerController.cs (8)
src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerResponseModel.cs (1)
  • PlayerResponseModel (11-26)
test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs (6)
  • PlayerResponseModel (222-237)
  • PlayerResponseModel (264-283)
  • PlayerResponseModel (310-313)
  • PlayerRequestModel (205-220)
  • PlayerRequestModel (243-262)
  • PlayerRequestModel (305-308)
src/Dotnet.Samples.AspNetCore.WebApi/Data/IPlayerRepository.cs (1)
  • Task (20-20)
src/Dotnet.Samples.AspNetCore.WebApi/Data/IRepository.cs (3)
  • Task (15-15)
  • Task (22-22)
  • Task (39-39)
src/Dotnet.Samples.AspNetCore.WebApi/Data/Repository.cs (4)
  • Task (10-14)
  • Task (16-16)
  • Task (20-24)
  • Task (26-34)
src/Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (7)
  • Task (48-56)
  • Task (62-91)
  • Task (93-97)
  • Task (99-103)
  • Task (109-125)
  • Task (131-146)
  • Task (154-162)
src/Dotnet.Samples.AspNetCore.WebApi/Validators/PlayerRequestModelValidator.cs (1)
  • Task (45-48)
src/Dotnet.Samples.AspNetCore.WebApi/Models/PlayerRequestModel.cs (1)
  • PlayerRequestModel (13-30)
🪛 GitHub Check: CodeFactor
scripts/run-migrations-and-copy-database.sh

[notice] 45-45: scripts/run-migrations-and-copy-database.sh#L45
Check exit code directly with e.g. 'if mycmd;', not indirectly with $?. (SC2181)


[notice] 34-34: scripts/run-migrations-and-copy-database.sh#L34
Check exit code directly with e.g. 'if ! mycmd;', not indirectly with $?. (SC2181)

src/Dotnet.Samples.AspNetCore.WebApi/Validators/PlayerRequestModelValidator.cs

[notice] 36-36: src/Dotnet.Samples.AspNetCore.WebApi/Validators/PlayerRequestModelValidator.cs#L36
Code should not contain empty statements. (SA1106)

🪛 GitHub Check: Codeac Code Quality
src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerData.cs

[warning] 203-218: CodeDuplication
This block of 15 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:62


[warning] 217-232: CodeDuplication
This block of 15 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:76


[warning] 231-246: CodeDuplication
This block of 15 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:90


[warning] 245-260: CodeDuplication
This block of 15 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:104


[warning] 259-274: CodeDuplication
This block of 15 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:118

test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs

[warning] 62-77: CodeDuplication
This block of 15 lines is too similar to src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerData.cs:203


[warning] 76-91: CodeDuplication
This block of 15 lines is too similar to src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerData.cs:217


[warning] 90-105: CodeDuplication
This block of 15 lines is too similar to src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerData.cs:231


[warning] 104-119: CodeDuplication
This block of 15 lines is too similar to src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerData.cs:245

test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs

[warning] 227-241: CodeDuplication
This block of 14 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs:393


[warning] 227-241: CodeDuplication
This block of 14 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs:393


[warning] 449-462: CodeDuplication
This block of 13 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs:263

test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs

[warning] 146-156: CodeDuplication
This block of 10 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:204


[warning] 216-222: CodeDuplication
This block of 6 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:157

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (57)
src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414195445_SeedStarting11.Designer.cs (1)

1-69: Auto-generated migration designer looks correct

This auto-generated migration design file properly implements the schema changes, including:

  • Using Guid as the primary key type for Player entities
  • Setting up the key to be value-generated
  • Configuring a unique index on SquadNumber
  • Making string properties nullable
  • Setting appropriate column types for all properties

The migration aligns with the broader refactoring goal of changing player identifiers from long to Guid while using SquadNumber as the public-facing identifier.

codecov.yml (1)

53-53: LGTM: Appropriate exclusion of scripts directory from code coverage

Adding the scripts directory to the ignore patterns ensures that utility scripts won't affect your code coverage metrics, which is appropriate since these are typically infrastructure/tooling code rather than application logic.

src/Dotnet.Samples.AspNetCore.WebApi/Dotnet.Samples.AspNetCore.WebApi.csproj (1)

31-31: Good practice: Conditional inclusion of SQLite database file

Adding the Condition="Exists('Data/players-sqlite3.db')" attribute prevents build failures when the database file doesn't exist, which supports the new database initialization workflow where the file might be generated at runtime.

.codacy.yml (1)

33-33: Looks good - appropriate exclusion for helper scripts.

The addition of scripts/**/* to the exclusion list is appropriate for helper shell scripts, which matches the PR's focus on refactoring player identifiers that includes new migration scripts.

src/Dotnet.Samples.AspNetCore.WebApi/Data/IPlayerRepository.cs (1)

17-20: Return type change from ValueTask to Task is appropriate.

The change from ValueTask<Player?> to Task<Player?> for FindBySquadNumberAsync aligns with the PR's goal of refactoring player identifiers. This method signature change is properly documented in the XML comments.

src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerDbContext.cs (1)

17-37: Entity configuration looks great and properly enforces constraints.

The override of OnModelCreating properly configures the Player entity with:

  1. Id as the primary key (Guid)
  2. Auto-generation of Id values
  3. A unique index on SquadNumber

This correctly implements the database-level constraints needed for the identifier refactoring and ensures SquadNumber uniqueness, which is essential for using it as a public-facing identifier. The XML documentation is thorough and clear.

src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerRepository.cs (1)

10-11: Return type change approved

The return type change from ValueTask<Player?> to Task<Player?> for the FindBySquadNumberAsync method maintains consistency with other asynchronous methods in the codebase and properly aligns with the interface definition.

src/Dotnet.Samples.AspNetCore.WebApi/Data/IRepository.cs (2)

32-32: ID type change approved

Changing the parameter type from long to Guid for FindByIdAsync aligns with the broader refactoring to use GUIDs as primary keys for entities. The return type ValueTask<T?> remains appropriate as it matches Entity Framework Core's FindAsync method.


46-46: ID type change approved

Changing the parameter type from long to Guid for RemoveAsync consistently applies the primary key type change throughout the interface. This aligns with the overall refactoring approach.

src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414191223_InitialCreate.cs (2)

35-39: Unique index on SquadNumber approved

Adding a unique index on the SquadNumber column enforces uniqueness at the database level, which is essential for using squad number as the main identifier for player operations. This is a good practice that prevents data integrity issues.


18-18:

❓ Verification inconclusive

Primary key type change approved

Changing the Id column type from long to Guid aligns with the refactoring goal of using GUIDs as primary keys. Make sure GUID generation is properly implemented when creating new Player entities.


🏁 Script executed:

#!/bin/bash
# Check how Player entities are created and how GUIDs are generated
rg -A 5 -B 5 "new Player\(" --type csharp

Length of output: 43


Primary key type change approved – additional manual verification required

The change from a long to a Guid for the primary key in the migration is correct and aligns with our refactoring goal. However, our search for where new Player entities are instantiated (specifically looking for "new Player(") returned no results. Please manually verify that GUID generation (e.g., via Guid.NewGuid()) is properly implemented when creating new Player instances.

  • Ensure that when a new Player is instantiated, a GUID is generated and assigned appropriately.
  • Double-check any factory methods, constructors, or service layers responsible for creating Player entities.
src/Dotnet.Samples.AspNetCore.WebApi/Data/Repository.cs (2)

18-18: ID type change approved

Changing the parameter type from long to Guid for FindByIdAsync correctly implements the updated interface while maintaining the appropriate implementation using _dbSet.FindAsync(id).


26-34: ID type change and implementation approved

The RemoveAsync method now correctly accepts a Guid parameter instead of long, maintaining consistency with the interface changes. The implementation correctly checks for the entity's existence before attempting to remove it, which prevents errors when trying to remove non-existent entities.

src/Dotnet.Samples.AspNetCore.WebApi/Data/PlayerData.cs (2)

143-154: Enhanced data structure with consistent property patterns.

The removal of explicit Id properties from player objects in MakeStarting11() aligns with the project's refactoring to use squad numbers as the primary player identifier in the API. This change is consistent with the broader shift in identifier strategy across the application.


325-457: JSON structure properly aligned with entity changes.

The updated JSON string correctly removes all "id" fields from the serialized player objects, which aligns with the application's new approach of not exposing internal IDs through the API. This maintains consistency with the Player model changes.

src/Dotnet.Samples.AspNetCore.WebApi/Services/IPlayerService.cs (2)

33-33: Updated parameter type for internal ID representation.

The parameter type change from long to Guid for the RetrieveByIdAsync method correctly aligns with the new Player entity design using GUIDs as internal identifiers.


55-57: Strategic shift to squad number as primary identifier.

The service method now correctly uses squad number for deletion instead of internal ID, which supports the architectural change to use squad numbers as the primary player identifier in API operations. The documentation has been properly updated to reflect this change.

src/Dotnet.Samples.AspNetCore.WebApi/Migrations/PlayerDbContextModelSnapshot.cs (3)

18-18: Updated EF Core product version.

The model snapshot has been updated to use Entity Framework Core 9.0.4.


22-25: Migrated primary key type to Guid.

The Id property has been correctly changed from long (INTEGER) to Guid (TEXT) as part of the entity refactoring strategy. This change is properly integrated with the ValueGeneratedOnAdd attribute to ensure automatic GUID generation.


58-60: Added unique constraint for squad numbers.

The unique index on SquadNumber is a critical addition that enforces data integrity at the database level. This ensures squad numbers are unique across all players, which is essential now that squad numbers are used as the primary identifier in API operations.

src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414195445_SeedStarting11.cs (2)

14-15: Consider null checks on returned player list.
If PlayerData.MakeStarting11WithId() returns an empty or null list, this loop will do nothing or throw an exception. Consider adding a null/empty check before looping to ensure safe seeding.


52-60: Validate Down migration data removal.
The Down method removes rows by matching GUID Id. This is correct, but ensure the Ids in PlayerData.MakeStarting11WithId() never change across versions; otherwise, Down may fail to find and remove them.

src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414191223_InitialCreate.Designer.cs (4)

14-14: Migration name alignment.
The updated migration name 20250414191223_InitialCreate matches the corresponding .cs file.


21-21: Product version upgrade noted.
The annotation now references EF 9.0.4. Confirm that the rest of your project is using EF 9.x to avoid version mismatch issues.


25-27: GUID for primary key is appropriate for SQLite.
Storing the GUID as TEXT is a standard EF pattern for SQLite. This aligns well with the new internal identifier approach.


61-63: Ensuring unique SquadNumber.
The unique index on SquadNumber enforces the new requirement. Verify that any domain logic includes meaningful error handling if a duplicate SquadNumber is inserted.

src/Dotnet.Samples.AspNetCore.WebApi/Validators/PlayerRequestModelValidator.cs (1)

19-24: Nice integration of repository-based validation.

The addition of _playerRepository via constructor injection enables repository-dependent validations. This is a good approach to maintain the validator's single responsibility. Just ensure that in tests or other environments, _playerRepository is properly mocked or stubbed.

src/Dotnet.Samples.AspNetCore.WebApi/Services/PlayerService.cs (2)

111-114: Validate the 'not found' path.

If no record is found for the provided squad number, the update operation silently exits. Consider explicitly handling or logging the "player not found" scenario to avoid silent failures.


93-93:

✅ Verification successful

Confirm all references to the new GUID signature.

The shift from a numeric Id to a GUID conforms to your new entity definition. Ensure all calling sites now pass a GUID to avoid mismatches.


🏁 Script executed:

#!/bin/bash
# Description: Search for any usage of RetrieveByIdAsync that might still be passing a numeric ID.
rg -A 3 'RetrieveByIdAsync\('

Length of output: 4398


Confirmed – All references now correctly utilize the GUID signature.

The search verifies that both the service and its tests (in PlayerServiceTests.cs and PlayerControllerTests.cs) consistently call RetrieveByIdAsync with a Guid. The usage of It.IsAny<Guid>() in the tests further confirms that the numeric ID has been fully replaced.

test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs (5)

21-21: Consistent refactoring of player identifiers to use GUIDs.

The change from hardcoded numeric IDs to dynamically generated GUIDs aligns well with the broader domain model changes, ensuring uniqueness of player identifiers.

Also applies to: 35-35, 49-49, 63-63, 77-77, 91-91, 105-105, 119-119, 133-133, 147-147, 159-159


173-182: Successfully refactored lookup method to use squad number instead of ID.

This change properly implements the shift from using ID to SquadNumber as the primary lookup mechanism, including appropriate error messaging.


243-262: Properly implemented squad number-based request model creation.

The method now correctly uses squad number instead of ID for retrieving the player, aligning with the new API design where squad number is the primary external identifier.


264-283: Successfully refactored response model creation to use squad number.

Similar to the request model changes, this method correctly implements the shift to squad number as the primary lookup key.


305-308: Appropriate update to model creation methods.

These methods have been correctly updated to use squad number instead of ID for identifying players in test data.

Also applies to: 310-313

test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs (6)

131-132: Properly updated test to use GUID for ID-based retrieval.

This change correctly adapts the test to use Guid instead of long for the player's ID, matching the domain model changes.


146-146: Successfully updated verification to check for Guid parameter.

The verification now correctly checks for a Guid parameter instead of a long, ensuring the test properly validates the updated service method signature.

Also applies to: 175-175

🧰 Tools
🪛 GitHub Check: Codeac Code Quality

[warning] 146-156: CodeDuplication
This block of 10 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:204


156-160: Test correctly uses both ID and squad number.

The test now properly uses both the Guid ID and integer squad number, reflecting the dual-identifier approach in the refactored application.


216-219: Properly adjusted test data for squad number-based retrieval.

The test now correctly uses the squad number to retrieve player and response model data.

🧰 Tools
🪛 GitHub Check: Codeac Code Quality

[warning] 216-222: CodeDuplication
This block of 6 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerServiceTests.cs:157


251-283: Successfully refactored update test to use squad number.

The test method name and implementation have been properly updated to reflect the new approach of finding players by squad number before updating them.


291-317: Successfully refactored delete test to use squad number.

Similar to the update test, this test now correctly validates that deletion works by finding a player by squad number and then removing it using the ID.

test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs (10)

49-49: Successfully updated verification to check squad number-based retrieval.

The tests now correctly verify that the controller calls the service's RetrieveBySquadNumberAsync method instead of RetrieveByIdAsync.

Also applies to: 92-92, 139-139


68-69: Test method names updated to reflect squad number-based retrieval.

The test method names have been properly updated to reflect the change from ID to squad number for player retrieval.

Also applies to: 111-112


215-215: Successfully updated ID-based tests to use GUID.

The GetByIdAsync tests now properly use Guid instead of long for the ID parameter, reflecting the domain model changes.

Also applies to: 240-241


227-227: Updated verification for ID-based tests to check for Guid parameter.

The verification now correctly checks that the service method was called with a Guid parameter.

Also applies to: 251-251

🧰 Tools
🪛 GitHub Check: Codeac Code Quality

[warning] 227-241: CodeDuplication
This block of 14 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs:393


291-293: Test correctly uses squad number for player retrieval.

The test now properly uses a realistic squad number (10) and retrieves the corresponding test data.


318-360: Successfully refactored PUT validation test to use squad number.

The test now correctly validates that the PUT endpoint properly handles validation errors when updating by squad number.


364-402: Successfully refactored PUT not found test to use squad number.

The test correctly verifies that the controller returns a 404 response when no player with the given squad number exists.


406-441: Successfully refactored PUT success test to use squad number.

The test properly validates that the controller updates a player by squad number and returns the expected response.

🧰 Tools
🪛 GitHub Check: Codeac Code Quality

[warning] 418-432: CodeDuplication
This block of 14 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs:76


449-471: Successfully refactored DELETE not found test to use squad number.

Similar to the PUT tests, this test correctly verifies that the DELETE endpoint returns a 404 response when no player with the given squad number exists.

🧰 Tools
🪛 GitHub Check: Codeac Code Quality

[warning] 449-462: CodeDuplication
This block of 13 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Unit/PlayerControllerTests.cs:263


475-499: Successfully refactored DELETE success test to use squad number.

The test properly validates that the controller deletes a player by squad number and returns the expected response.

src/Dotnet.Samples.AspNetCore.WebApi/Controllers/PlayerController.cs (7)

5-5: Added authorization namespace.

This supports the new Admin role authorization requirement for the GetByIdAsync endpoint.


30-30: Successfully refactored POST endpoint to use squad number.

The POST endpoint now correctly:

  1. Uses "Create" as the route name
  2. Checks for existing players by squad number instead of ID
  3. Returns a CreatedAtRoute result that points to the RetrieveBySquadNumber endpoint with the correct squad number

Also applies to: 49-54, 62-64


77-77: Updated GET endpoint route name.

The route name has been standardized to "Retrieve" for consistency with other endpoints.


102-107: Properly secured ID-based retrieval endpoint.

This important security change:

  1. Restricts the ID-based endpoint to Admin users
  2. Hides it from the API explorer to discourage direct use
  3. Changes the route to use Guid instead of long for the ID
  4. Updates the route name to "RetrieveById"

128-128: Updated squad number route for clarity.

The route path has been changed from "squad/{squadNumber:int}" to "squadNumber/{squadNumber:int}" for better clarity, and the route name updated to "RetrieveBySquadNumber".


155-160: Successfully refactored PUT endpoint to use squad number.

The PUT endpoint has been properly updated to:

  1. Use squad number instead of ID in the route and method signature
  2. Update documentation to reference squad number
  3. Change the route name to "Update"
  4. Update logging to reference squad number
  5. Use the RetrieveBySquadNumberAsync service method

The implementation correctly maintains the existing validation and error handling logic while adapting to the new identifier approach.

Also applies to: 163-171, 180-194


202-221: Successfully refactored DELETE endpoint to use squad number.

Similar to the PUT endpoint, the DELETE endpoint has been properly updated to:

  1. Use squad number instead of ID in the route and method signature
  2. Update documentation to reference squad number
  3. Change the route name to "Delete"
  4. Update logging to reference squad number
  5. Use the appropriate service methods for retrieval and deletion

The implementation correctly maintains the existing error handling logic while adapting to the new identifier approach.

Comment on lines +19 to +25
FirstName = table.Column<string>(type: "TEXT", nullable: true),
MiddleName = table.Column<string>(type: "TEXT", nullable: true),
LastName = table.Column<string>(type: "TEXT", nullable: false),
LastName = table.Column<string>(type: "TEXT", nullable: true),
DateOfBirth = table.Column<DateTime>(type: "TEXT", nullable: true),
SquadNumber = table.Column<int>(type: "INTEGER", nullable: false),
Position = table.Column<string>(type: "TEXT", nullable: false),
AbbrPosition = table.Column<string>(type: "TEXT", nullable: false),
Position = table.Column<string>(type: "TEXT", nullable: true),
AbbrPosition = table.Column<string>(type: "TEXT", nullable: true),
Copy link

@coderabbitai coderabbitai bot Apr 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify null handling for previously non-nullable columns

Several columns that were previously non-nullable are now nullable (FirstName, LastName, Position, AbbrPosition, DateOfBirth). Ensure that the application code correctly handles potential null values to prevent null reference exceptions.


🏁 Script executed:

#!/bin/bash
# Check for null checks or null-conditional operators on these properties
rg "\.FirstName|\.LastName|\.Position|\.AbbrPosition|\.DateOfBirth" --type csharp -A 2 -B 2

Length of output: 10541


Null Handling in Migration & Mapping: Action Needed

After verifying the changes, please note the following:

  • The migration now allows nulls for several columns (FirstName, LastName, Position, AbbrPosition, DateOfBirth).
  • The validator (PlayerRequestModelValidator.cs) enforces non-null/empty values for FirstName, LastName, and AbbrPosition, but there’s no corresponding check for DateOfBirth or Position.
  • In the mapping profile (PlayerMappingProfile.cs), the DateOfBirth property is formatted directly using string interpolation ($"{source.DateOfBirth:MMMM d, yyyy}"), which can throw an exception if DateOfBirth is null.
  • Test files currently provide values for these columns, but null scenarios may occur in production.

Recommendations:

  • DateOfBirth: Update the mapping to safely handle null values (e.g., use a conditional to supply a default string or check for HasValue) or enforce non-null validation if a value is required.
  • Position: Confirm that the intended behavior for nullable Position is correctly managed in both validation and mapping scenarios.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open a follow-up GitHub issue for this discussion.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

@nanotaboada I've created a GitHub issue to track the null handling concerns for the newly nullable columns. The issue includes:

  • Background information about the changes made in this PR
  • Specific issues identified regarding DateOfBirth and Position fields
  • Recommended actions for proper null handling
  • References back to this PR and our discussion

The issue is assigned to you for follow-up after this PR is completed.

🐰✍️


🏁 Script executed:

#!/bin/bash
# Create a GitHub issue for null handling concerns

gh issue create \
  --title "Fix null handling for newly nullable columns in Player entity" \
  --body "## Background

In PR #208 (feature/identifiers), several columns in the Player entity were changed from non-nullable to nullable:
- FirstName
- LastName
- Position
- AbbrPosition
- DateOfBirth

## Issues Identified

The code review identified potential null handling concerns:

1. The validator (`PlayerRequestModelValidator.cs`) enforces non-null/empty values for FirstName, LastName, and AbbrPosition, but there's no corresponding check for DateOfBirth or Position.

2. In the mapping profile (`PlayerMappingProfile.cs`), the DateOfBirth property is formatted directly using string interpolation (\`$\"{source.DateOfBirth:MMMM d, yyyy}\"\`), which can throw an exception if DateOfBirth is null.

3. While test files currently provide values for these columns, null scenarios may occur in production.

## Recommended Actions

- **DateOfBirth:** Update the mapping to safely handle null values (e.g., use a conditional to supply a default string or check for HasValue) or enforce non-null validation if a value is required.
- **Position:** Confirm that the intended behavior for nullable Position is correctly managed in both validation and mapping scenarios.

## References
- PR: https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/pull/208
- Discussion: https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/pull/208#discussion_r2045389913" \
  --assignee "nanotaboada"

echo "Issue created successfully."

Length of output: 1863


@nanotaboada I've successfully created a GitHub issue to track the null handling concerns: Issue #209.

The issue contains all the details about the nullable columns changed in this PR, the specific concerns with DateOfBirth and Position handling, and recommended actions. It's assigned to you for follow-up once this PR is completed.

🐰 📝


🧬 Code Graph Analysis Results

Possibly relevant snippets from src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414195445_SeedStarting11.cs

At line range 12-50:

protected override void Up(MigrationBuilder migrationBuilder)
{
    var starting11 = PlayerData.MakeStarting11WithId();

    foreach (var player in starting11)
    {
        migrationBuilder.InsertData(
            table: "Players",
            columns:
            [
                "Id",
                "FirstName",
                "MiddleName",
                "LastName",
                "DateOfBirth",
                "SquadNumber",
                "Position",
                "AbbrPosition",
                "Team",
                "League",
                "Starting11"
            ],
            values: new object[]
            {
                player.Id,
                player.FirstName,
                player.MiddleName,
                player.LastName,
                player.DateOfBirth,
                player.SquadNumber,
                player.Position,
                player.AbbrPosition,
                player.Team,
                player.League,
                player.Starting11
            }
        );
    }
}

At line range 53-60:

protected override void Down(MigrationBuilder migrationBuilder)
{
    var starting11 = PlayerData.MakeStarting11WithId();
    foreach (var player in starting11)
    {
        migrationBuilder.DeleteData(table: "Players", keyColumn: "Id", keyValue: player.Id);
    }
}

Possibly relevant snippets from test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/DatabaseFakes.cs

At line range 36-47:

public static void CreateTable(this PlayerDbContext context)
{
    using var cmd = context.Database.GetDbConnection().CreateCommand();
    cmd.CommandText =
        @"
        CREATE TABLE players (
            id INTEGER PRIMARY KEY,
            firstName TEXT NOT NULL,
            /* ... other columns ... */
        )";
    cmd.ExecuteNonQuery();
}

This snippet shows a method to create a players table in a test database context, which may relate to the schema defined in the migration.

Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/Dotnet.Samples.AspNetCore.WebApi/Utilities/PlayerData.cs (2)

143-153: Team name inconsistency in player data

There's a potential inconsistency in the team name for Julián Álvarez. In this instance, the team is listed as "Manchester City", but in the JSON data (line 453), it's "Manchester City" as well, while for other teams like "Atlético Madrid", there are spelling inconsistencies between the hardcoded data and JSON representation (compare "Altético Madrid" on line 183 with "Atlético Madrid" on line 345).

-                Team = "Manchester City",
+                Team = "Manchester City FC",

Additionally, fix the spelling of "Altético Madrid" to "Atlético Madrid" in both instances for consistency.


183-183: Fix team name spelling inconsistencies

The team name "Altético Madrid" is misspelled in both instances. It should be "Atlético Madrid" as correctly shown in the JSON data (lines 345 and 405).

-                Team = "Altético Madrid",
+                Team = "Atlético Madrid",

Also applies to: 253-253

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 58a115f and fa6abd1.

📒 Files selected for processing (5)
  • src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414195445_SeedStarting11.cs (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Program.cs (1 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Utilities/ApplicationBuilderExtensions.cs (0 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Utilities/DbContextUtils.cs (0 hunks)
  • src/Dotnet.Samples.AspNetCore.WebApi/Utilities/PlayerData.cs (3 hunks)
💤 Files with no reviewable changes (2)
  • src/Dotnet.Samples.AspNetCore.WebApi/Utilities/ApplicationBuilderExtensions.cs
  • src/Dotnet.Samples.AspNetCore.WebApi/Utilities/DbContextUtils.cs
✅ Files skipped from review due to trivial changes (1)
  • src/Dotnet.Samples.AspNetCore.WebApi/Program.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Dotnet.Samples.AspNetCore.WebApi/Migrations/20250414195445_SeedStarting11.cs
🧰 Additional context used
🪛 GitHub Check: Codeac Code Quality
src/Dotnet.Samples.AspNetCore.WebApi/Utilities/PlayerData.cs

[warning] 259-274: CodeDuplication
This block of 15 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:118


[warning] 273-287: CodeDuplication
This block of 14 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:132

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (3)
src/Dotnet.Samples.AspNetCore.WebApi/Utilities/PlayerData.cs (3)

5-5: Namespace change aligns with the utility nature of this class

The namespace change from Dotnet.Samples.AspNetCore.WebApi.Data to Dotnet.Samples.AspNetCore.WebApi.Utilities is appropriate as this class provides utility methods for creating player data rather than being directly involved in data access.


156-312: Good addition of the MakeStarting11WithId method for database seeding

The addition of MakeStarting11WithId() is a good implementation for seeding data with specific GUIDs. This allows for predictable IDs in database migrations, which is important for:

  1. Maintaining referential integrity
  2. Enabling consistent testing against known data
  3. Supporting repeatable deployments

Consistent with the refactoring to use GUID as the internal primary key for the Player entity.

🧰 Tools
🪛 GitHub Check: Codeac Code Quality

[warning] 259-274: CodeDuplication
This block of 15 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:118


[warning] 273-287: CodeDuplication
This block of 14 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:132


[warning] 286-301: CodeDuplication
This block of 15 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:145


320-320: Method rename clarifies its purpose

Renaming to MakeStarting11FromDeserializedJson() provides a clearer description of what the method does, making the codebase more maintainable and self-documenting.

Comment on lines +259 to +287
Id = Guid.Parse("198c4774-9607-4e76-8475-ec2528af69d2"),
FirstName = "Enzo",
MiddleName = "Jeremías",
LastName = "Fernández",
DateOfBirth = new DateTime(2001, 1, 16, 0, 0, 0, DateTimeKind.Utc),
SquadNumber = 24,
Position = Position.CentralMidfield.Text,
AbbrPosition = Position.CentralMidfield.Abbr,
Team = "Chelsea FC",
League = "Premier League",
Starting11 = true,
},
new()
{
Id = Guid.Parse("06971ada-1b3d-4d4a-88f5-e2f35311b5aa"),
FirstName = "Alexis",
LastName = "Mac Allister",
DateOfBirth = new DateTime(1998, 12, 23, 0, 0, 0, DateTimeKind.Utc),
SquadNumber = 20,
Position = Position.CentralMidfield.Text,
AbbrPosition = Position.CentralMidfield.Abbr,
Team = "Liverpool FC",
League = "Premier League",
Starting11 = true,
},
new()
{
Id = Guid.Parse("df6f6bab-5efd-4518-80bb-09ef54435636"),
FirstName = "Lionel",
Copy link

@coderabbitai coderabbitai bot Apr 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Consider addressing code duplication with test utilities

Static analysis tools identified code duplication between this class and PlayerFakes.cs in the test utilities. Consider extracting common player data definitions to a shared location or ensuring the test utilities reference this class directly to maintain a single source of truth.


🏁 Script executed:

#!/bin/bash
# Check the content of the PlayerFakes.cs file to understand the duplication
fd --type file -e cs "PlayerFakes.cs" | xargs cat

Length of output: 11698


Refactor Duplicate Player Data Definitions

The production file (src/Dotnet.Samples.AspNetCore.WebApi/Utilities/PlayerData.cs) and the test utility (PlayerFakes.cs) both include nearly identical player data—only minor differences like using a fixed GUID versus generating new ones differentiate them. To simplify future maintenance and ensure consistency, please consider one of the following approaches:

  • Extract a Shared Player Data Module: Consolidate the common player data definitions into a single shared module that both production and test utilities can reference.
  • Reference the Existing Production Data: Update the test utilities to directly reference the production implementation, ensuring a single source of truth.
🧰 Tools
🪛 GitHub Check: Codeac Code Quality

[warning] 259-274: CodeDuplication
This block of 15 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:118


[warning] 273-287: CodeDuplication
This block of 14 lines is too similar to test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs:132

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open a follow-up GitHub issue for this discussion.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Create a GitHub issue for the code duplication problem

# Define the issue title
TITLE="Refactor duplicate player data definitions between PlayerData and PlayerFakes"

# Define the issue body with context, analysis, and proposed solutions
BODY="## Description

Code duplication was identified between \`src/Dotnet.Samples.AspNetCore.WebApi/Utilities/PlayerData.cs\` and \`test/Dotnet.Samples.AspNetCore.WebApi.Tests/Utilities/PlayerFakes.cs\`. Both files contain nearly identical player data definitions with only minor differences (like using fixed GUIDs versus generating new ones).

This duplication increases maintenance overhead and risk of inconsistencies when player data needs to be updated.

## Proposed Solutions

Consider one of the following approaches:

1. **Extract a Shared Player Data Module**: Consolidate the common player data definitions into a single shared module that both production and test utilities can reference.

2. **Reference the Existing Production Data**: Update the test utilities to directly reference the production implementation, ensuring a single source of truth.

## Context

This issue was identified during a code review of PR #208.

## References
- PR discussion: https://github.com/nanotaboada/Dotnet.Samples.AspNetCore.WebApi/pull/208#discussion_r2045424185"

# Create the issue and assign it to nanotaboada
gh issue create --repo nanotaboada/Dotnet.Samples.AspNetCore.WebApi --title "$TITLE" --body "$BODY" --assignee "nanotaboada"

Length of output: 2469


@nanotaboada I've created a follow-up GitHub issue as requested. The issue has been assigned to you and can be found here: #210

The issue details the code duplication between PlayerData.cs and PlayerFakes.cs and suggests potential solutions for addressing this in a future update.

@nanotaboada nanotaboada merged commit a06a111 into master Apr 15, 2025
24 checks passed
@nanotaboada nanotaboada deleted the feature/identifiers branch April 15, 2025 20:32
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.

Refactor to use Guid as internal Id and SquadNumber as public identifier
1 participant