From f1c0021ad30672f99b5659b8e4c5a8ad6baa620b Mon Sep 17 00:00:00 2001 From: Simon Dellenbach Date: Mon, 3 Nov 2025 15:09:09 +0100 Subject: [PATCH] Use a local SQLite3 backend instead of PostgreSQL Docker container. * The provided SQLite3 database contains the required schemas, but no data and can be reset to if required. * Remove all references to PostgreSQL in documentation and configuration. * Replace native sqlite3 command with a console app to remove dependency on SQLite3 installation. --- .dockerignore | 4 -- Dockerfile | 8 ---- README.md | 42 +++-------------- docker-compose.yaml | 36 -------------- service.sln | 80 +++++++++++++++++--------------- service/Program.cs | 7 ++- service/appsettings.Docker.json | 3 -- service/appsettings.json | 4 +- service/service.csproj | 14 ++---- service/service.db | Bin 0 -> 12288 bytes show-posts/Post.cs | 24 ++++++++++ show-posts/PostsDbContext.cs | 20 ++++++++ show-posts/Program.cs | 4 ++ show-posts/show-posts.csproj | 17 +++++++ 14 files changed, 124 insertions(+), 139 deletions(-) delete mode 100644 .dockerignore delete mode 100644 Dockerfile delete mode 100644 docker-compose.yaml delete mode 100644 service/appsettings.Docker.json create mode 100644 service/service.db create mode 100644 show-posts/Post.cs create mode 100644 show-posts/PostsDbContext.cs create mode 100644 show-posts/Program.cs create mode 100644 show-posts/show-posts.csproj diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 294268c..0000000 --- a/.dockerignore +++ /dev/null @@ -1,4 +0,0 @@ -Dockerfile -docker-compose.yaml -[b|B]in -[O|o]bj diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index ee7580d..0000000 --- a/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -# Normally, we would use a multi-stage build, but for simplicity, we are using a single stage here. -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build -WORKDIR /src -COPY . . -RUN dotnet restore \ - && dotnet publish -c release -o /app -WORKDIR /app -ENTRYPOINT ["dotnet", "service.dll"] diff --git a/README.md b/README.md index 281ebf9..621713d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This exercise is designed to test your skills in C# and .NET. * .NET 8.0 / C# * Minimal ASP.NET Core Web API * Entity Framework Core -* PostgreSQL Database (Docker) +* SQLite3 Database (simplified for portability) * HttpClient for downstream REST API calls * ??? @@ -49,15 +49,11 @@ sequenceDiagram **Success Criteria: Verify that the post has been saved with the database with:** ```bash -$ docker compose exec --env PGPASSWORD=password db psql -h localhost -U user --db mydatabase -c "select * from posts;" +$ dotnet run --project show-posts/ - id | user_id | title | body | updated_at -----+---------+----------------------------------------------------------------------------+-----------------------------------------------------+------------------------ - 1 | 1 | sunt aut facere repellat provident occaecati excepturi optio reprehenderit | quia et suscipit +| 1970-01-01 00:00:00+00 - | | | suscipit recusandae consequuntur expedita et cum +| - | | | reprehenderit molestiae ut ut quas totam +| - | | | nostrum rerum est autem sunt rem eveniet architecto | -(1 row) +| Id | UserId | Title | Body | UpdatedAt | +| -- | ------ | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | +| 1 | 1 | sunt aut facere repellat provident occaecati excepturi optio reprehenderit | quia et suscipit suscipit recusandae consequuntur expedita et cum reprehenderit molestiae ut ut quas totam nostrum rerum est autem sunt rem eveniet architecto | 1/1/1970 12:00:00 AM +00:00 | ``` ### Phase 2 @@ -105,34 +101,10 @@ $ docker compose exec --env PGPASSWORD=password db psql -h localhost -U user --d ## Troubleshooting -### Start database manually - -Open a terminal at the repo root and execute - -```bash -$ docker compose up -d db - -[+] Running 3/3 - ✔ Network dotnet-interview-exercise_default Created 0.0s - ✔ Volume "dotnet-interview-exercise_db_data" Created 0.0s - ✔ Container dotnet-interview-exercise-db-1 Started 0.1s -``` - ### Cleanup database -In case something went wrong, wipe and rebuild the database +In case something went wrong or you want to start over, wipe the database by resetting the SQLite file. ```bash -$ docker compose down -v - -[+] Running 3/3 - ✔ Container dotnet-interview-exercise-db-1 Removed. 0.2s - ✔ Network dotnet-interview-exercise_default Removed. 0.2s - ✔ Volume dotnet-interview-exercise_db_data Removed. 0.0s - -$ docker compose up -d db -[+] Running 3/3 - ✔ Network dotnet-interview-exercise_default Created 0.0s - ✔ Volume "dotnet-interview-exercise_db_data" Created 0.0s - ✔ Container dotnet-interview-exercise-db-1 Started 0.1s +git restore service/service.db ``` diff --git a/docker-compose.yaml b/docker-compose.yaml deleted file mode 100644 index 76e9eca..0000000 --- a/docker-compose.yaml +++ /dev/null @@ -1,36 +0,0 @@ -services: - service: - build: - context: . - dockerfile: Dockerfile - depends_on: - - db - networks: - - default - ports: - - "8080:8080" - environment: - ASPNETCORE_ENVIRONMENT: Docker - - db: - image: postgres:alpine - restart: unless-stopped - networks: - - default - ports: - - "5432:5432" # Also for local development - environment: - POSTGRES_USER: user - POSTGRES_PASSWORD: password - POSTGRES_DB: mydatabase - volumes: - - db_data:/var/lib/postgresql/data - - ./dbschemas:/docker-entrypoint-initdb.d - -networks: - default: - driver: bridge - -volumes: - db_data: - driver: local diff --git a/service.sln b/service.sln index 42b7688..4675c3d 100644 --- a/service.sln +++ b/service.sln @@ -1,38 +1,42 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31903.59 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "service", "service\service.csproj", "{8572A3DF-7A4C-4552-8B30-22D794E703A6}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" - ProjectSection(SolutionItems) = preProject - docker-compose.yaml = docker-compose.yaml - Dockerfile = Dockerfile - README.md = README.md - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dbschemas", "dbschemas", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" - ProjectSection(SolutionItems) = preProject - dbschemas\01-create-posts-table.sql = dbschemas\01-create-posts-table.sql - dbschemas\02-posts-add-updated.sql = dbschemas\02-posts-add-updated.sql - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {8572A3DF-7A4C-4552-8B30-22D794E703A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8572A3DF-7A4C-4552-8B30-22D794E703A6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8572A3DF-7A4C-4552-8B30-22D794E703A6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8572A3DF-7A4C-4552-8B30-22D794E703A6}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {DD652F00-A6DC-4579-AF4C-12EA8B5C7ECC} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "service", "service\service.csproj", "{8572A3DF-7A4C-4552-8B30-22D794E703A6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}" + ProjectSection(SolutionItems) = preProject + README.md = README.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dbschemas", "dbschemas", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" + ProjectSection(SolutionItems) = preProject + dbschemas\01-create-posts-table.sql = dbschemas\01-create-posts-table.sql + dbschemas\02-posts-add-updated.sql = dbschemas\02-posts-add-updated.sql + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "show-posts", "show-posts\show-posts.csproj", "{D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8572A3DF-7A4C-4552-8B30-22D794E703A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8572A3DF-7A4C-4552-8B30-22D794E703A6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8572A3DF-7A4C-4552-8B30-22D794E703A6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8572A3DF-7A4C-4552-8B30-22D794E703A6}.Release|Any CPU.Build.0 = Release|Any CPU + {D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D73F984F-F3CA-4CFD-AF1A-EDE2D688294C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DD652F00-A6DC-4579-AF4C-12EA8B5C7ECC} + EndGlobalSection +EndGlobal diff --git a/service/Program.cs b/service/Program.cs index afc49f9..9d89c75 100644 --- a/service/Program.cs +++ b/service/Program.cs @@ -21,10 +21,9 @@ services.AddEndpointsApiExplorer(); services.AddSwaggerGen(); services.AddDbContext(optionsBuilder => { - // Configure the database connection string. - var connectionString = builder.Configuration.GetValue("PostgresConnection"); - Console.WriteLine($"Connecting to PostgreSQL database with connection string: {connectionString}"); - optionsBuilder.UseNpgsql(connectionString); + var connectionString = builder.Configuration.GetValue("SqliteConnection"); + Console.WriteLine($"Setting up SQLite database with {connectionString}"); + optionsBuilder.UseSqlite(connectionString); }); var httpClientBuilder = services.AddHttpClient(); diff --git a/service/appsettings.Docker.json b/service/appsettings.Docker.json deleted file mode 100644 index 62ea203..0000000 --- a/service/appsettings.Docker.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "PostgresConnection": "Server=db;Database=mydatabase;User Id=user;Password=password;" -} diff --git a/service/appsettings.json b/service/appsettings.json index 5b9f5e1..6ea2119 100644 --- a/service/appsettings.json +++ b/service/appsettings.json @@ -7,5 +7,5 @@ } }, "AllowedHosts": "*", - "PostgresConnection": "Server=localhost;Database=mydatabase;User Id=user;Password=password;" -} + "SqliteConnection": "Data Source=service.db" +} \ No newline at end of file diff --git a/service/service.csproj b/service/service.csproj index 40a28cc..dad1537 100644 --- a/service/service.csproj +++ b/service/service.csproj @@ -6,15 +6,11 @@ - - - - - + + + + + - - - - diff --git a/service/service.db b/service/service.db new file mode 100644 index 0000000000000000000000000000000000000000..a0a71a1f9c13cf61d040dd23da593015fb294684 GIT binary patch literal 12288 zcmeI#K}*9h6bJCMipp@Cw;sH_qk|!cXTdt77Q1d{89EP^j#enlRo4vkD1Iw%ev^Fw zkA48t$cCHj0)}@j00k?UhK6G^P$0p6gRvcuiOI=#uy9rZmozQK;))Ao)2L z6tpA-UElwys#FaUlKe&|=L-ESewojg>NI|gBbCIVZo8$|XbpoIK}G1KrJs(O6|B4$Zy71G5yp{MMpnxkyyM z7So6!009U<00Izz00bZa0SG_<0uWdsfl_f7^#3dLM{yMhKmY;|fB*y_009U<00Izz Hz+ZuHKXh9J literal 0 HcmV?d00001 diff --git a/show-posts/Post.cs b/show-posts/Post.cs new file mode 100644 index 0000000..2281c27 --- /dev/null +++ b/show-posts/Post.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +[Table("posts")] +public class Post +{ + [Key] + [Column("id")] + public int Id { get; set; } + + [Column("user_id")] + public int UserId { get; set; } + + [Column("title")] + [Required] + public string Title { get; set; } = string.Empty; + + [Column("body")] + [Required] + public string Body { get; set; } = string.Empty; + + [Column("updated_at")] + public DateTimeOffset UpdatedAt { get; set; } = DateTimeOffset.Parse("1970-01-01T00:00:00Z"); // TODO: Remove the default value in Phase 3. +} \ No newline at end of file diff --git a/show-posts/PostsDbContext.cs b/show-posts/PostsDbContext.cs new file mode 100644 index 0000000..4849cea --- /dev/null +++ b/show-posts/PostsDbContext.cs @@ -0,0 +1,20 @@ +using Microsoft.EntityFrameworkCore; + +public class PostsDbContext : DbContext +{ + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + var currentDir = System.IO.Directory.GetCurrentDirectory(); + int showPostsIndex = currentDir.IndexOf("show-posts"); + if (showPostsIndex > -1) + { + // Running from the bin directory, get the parent of "show-posts". + currentDir = currentDir.Substring(0, showPostsIndex - 1); + } + string repoRoot = currentDir; + + optionsBuilder.UseSqlite($"Data Source={repoRoot}/service/service.db;Mode=ReadOnly;"); + } + + public DbSet Posts { get; set; } +} diff --git a/show-posts/Program.cs b/show-posts/Program.cs new file mode 100644 index 0000000..62fd3f6 --- /dev/null +++ b/show-posts/Program.cs @@ -0,0 +1,4 @@ +using table.lib; + +using var context = new PostsDbContext(); +Table.Add(context.Posts.ToList()).ToConsole(); diff --git a/show-posts/show-posts.csproj b/show-posts/show-posts.csproj new file mode 100644 index 0000000..abd1728 --- /dev/null +++ b/show-posts/show-posts.csproj @@ -0,0 +1,17 @@ + + + + Exe + net8.0 + show_posts + enable + enable + + + + + + + + +