Skip to content

Commit fe63c18

Browse files
committed
nuget package upgrades
1 parent 62b4cde commit fe63c18

File tree

47 files changed

+1653
-1836
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1653
-1836
lines changed

.github/workflows/main.yml

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,73 @@
1-
name: Deploy NuGet Package
1+
name: Publish NuGet Package
22

33
env:
4-
PROJECT_PATH: './src/SharedKernel.Postgres/SharedKernel.Postgres.csproj'
5-
OUTPUT_DIR: 'nupkgs'
6-
NUGET_SOURCE: 'https://api.nuget.org/v3/index.json'
7-
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
4+
PROJECT_PATH: src/SharedKernel.Postgres/SharedKernel.Postgres.csproj
5+
OUTPUT_DIR: nupkgs
6+
NUGET_SOURCE: https://api.nuget.org/v3/index.json
87

98
on:
109
push:
11-
branches:
12-
- main
10+
branches: [main]
11+
12+
permissions:
13+
contents: read
14+
1315
jobs:
14-
deploy:
16+
publish:
1517
runs-on: ubuntu-latest
1618

1719
steps:
1820
- name: Checkout
1921
uses: actions/checkout@v6
2022

21-
- name: Setup .NET Core
23+
- name: Setup .NET
2224
uses: actions/setup-dotnet@v5
2325
with:
2426
global-json-file: global.json
2527

28+
- name: Restore
29+
run: dotnet restore ${{ env.PROJECT_PATH }}
30+
2631
- name: Build
27-
run: dotnet build ${{ env.PROJECT_PATH }}
32+
run: dotnet build ${{ env.PROJECT_PATH }} --no-restore --configuration Release
33+
34+
# - name: Test
35+
# run: dotnet test --no-build --configuration Release --verbosity normal
2836

2937
- name: Pack
30-
run: dotnet pack ${{ env.PROJECT_PATH }} --output ${{ env.OUTPUT_DIR }}
38+
run: dotnet pack ${{ env.PROJECT_PATH }} --no-build --configuration Release --output ${{ env.OUTPUT_DIR }}
3139

3240
- name: Publish
33-
run: dotnet nuget push ${{ env.OUTPUT_DIR }}/*.nupkg -k ${{ env.NUGET_API_KEY }} -s ${{ env.NUGET_SOURCE }}
41+
env:
42+
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
43+
shell: bash
44+
run: |
45+
set -euo pipefail
46+
47+
if [ -z "${NUGET_API_KEY:-}" ]; then
48+
echo "NUGET_API_KEY secret is not set."
49+
exit 1
50+
fi
51+
52+
shopt -s nullglob
53+
54+
nupkgs=( "${{ env.OUTPUT_DIR }}"/*.nupkg )
55+
snupkgs=( "${{ env.OUTPUT_DIR }}"/*.snupkg )
56+
57+
if [ ${#nupkgs[@]} -eq 0 ]; then
58+
echo "No .nupkg files found in ${{ env.OUTPUT_DIR }}"
59+
ls -la "${{ env.OUTPUT_DIR }}" || true
60+
exit 1
61+
fi
62+
63+
dotnet nuget push "${nupkgs[@]}" \
64+
--api-key "$NUGET_API_KEY" \
65+
--source "${{ env.NUGET_SOURCE }}" \
66+
--skip-duplicate
67+
68+
if [ ${#snupkgs[@]} -gt 0 ]; then
69+
dotnet nuget push "${snupkgs[@]}" \
70+
--api-key "$NUGET_API_KEY" \
71+
--source "${{ env.NUGET_SOURCE }}" \
72+
--skip-duplicate
73+
fi

README.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# Pandatech.SharedKernel.Postgres
2+
3+
PostgreSQL integration helpers for ASP.NET Core 10. Wraps Npgsql, Entity Framework Core, health checks, exception
4+
mapping, query locks, snake_case naming, and audit trail wiring into a small set of extension methods so every service
5+
starts from the same consistent baseline.
6+
7+
Requires **.NET 10.0**. Uses C# 14 extension members and cannot be downgraded.
8+
9+
---
10+
11+
## Table of Contents
12+
13+
1. [Installation](#installation)
14+
2. [What is included](#what-is-included)
15+
3. [Registering a DbContext](#registering-a-dbcontext)
16+
4. [Migrations](#migrations)
17+
5. [Model configuration helpers](#model-configuration-helpers)
18+
6. [Health checks](#health-checks)
19+
20+
---
21+
22+
## Installation
23+
24+
```bash
25+
dotnet add package Pandatech.SharedKernel.Postgres
26+
```
27+
28+
---
29+
30+
## What is included
31+
32+
Every `AddPostgresContext*` overload automatically applies the following to your DbContext:
33+
34+
| Feature | Source package |
35+
|-----------------------------------|---------------------------------------------|
36+
| Npgsql provider | `Npgsql.EntityFrameworkCore.PostgreSQL` |
37+
| Snake_case naming convention | `EFCore.NamingConventions` |
38+
| Query locks (`FOR UPDATE` etc.) | `Pandatech.EFCore.PostgresExtensions` |
39+
| Friendly exception mapping | `EntityFrameworkCore.Exceptions.PostgreSQL` |
40+
| `AuditBase` property validation | `Pandatech.EFCore.AuditBase` |
41+
| Audit trail interceptors (opt-in) | `Pandatech.EFCore.Audit` |
42+
| Postgres health check | `AspNetCore.HealthChecks.NpgSql` |
43+
| Bulk extensions | `EFCore.BulkExtensions.PostgreSql` |
44+
| Gridify query extensions | `Pandatech.GridifyExtensions` |
45+
46+
---
47+
48+
## Registering a DbContext
49+
50+
All overloads are on `WebApplicationBuilder` and return `WebApplicationBuilder` for chaining. Every variant
51+
automatically registers a Postgres health check named `postgres_{DatabaseName}`.
52+
53+
### Basic registration (no pooling, no audit trail)
54+
55+
```csharp
56+
// Minimal — connection string only
57+
builder.AddPostgresContext<AppDbContext>(connectionString);
58+
59+
// With migrations assembly by name
60+
builder.AddPostgresContext<AppDbContext>(connectionString, "MyApp.Migrations");
61+
62+
// With migrations assembly by Assembly reference
63+
builder.AddPostgresContext<AppDbContext>(connectionString, typeof(Program).Assembly);
64+
65+
// With migrations assembly by marker type
66+
builder.AddPostgresContext<AppDbContext, Program>(connectionString);
67+
68+
// Full control via NpgsqlDbContextOptionsBuilder callback
69+
builder.AddPostgresContext<AppDbContext>(connectionString, npgsql =>
70+
{
71+
npgsql.MigrationsAssembly("MyApp.Migrations");
72+
npgsql.CommandTimeout(60);
73+
});
74+
```
75+
76+
### With connection pooling
77+
78+
Same set of overloads, prefixed with `Pool`:
79+
80+
```csharp
81+
builder.AddPostgresContextPool<AppDbContext>(connectionString);
82+
builder.AddPostgresContextPool<AppDbContext>(connectionString, "MyApp.Migrations");
83+
builder.AddPostgresContextPool<AppDbContext, Program>(connectionString);
84+
builder.AddPostgresContextPool<AppDbContext>(connectionString, npgsql => { ... });
85+
```
86+
87+
Use pooling for high-throughput services. Note that DbContext pooling requires that your context has no scoped
88+
dependencies injected via the constructor; use service provider overloads (`(sp, options) => ...`) for those cases.
89+
90+
### With audit trail (no pooling)
91+
92+
Registers the `Pandatech.EFCore.Audit` interceptors alongside the standard options:
93+
94+
```csharp
95+
builder.AddPostgresContextWithAuditTrail<AppDbContext>(connectionString);
96+
builder.AddPostgresContextWithAuditTrail<AppDbContext>(connectionString, "MyApp.Migrations");
97+
builder.AddPostgresContextWithAuditTrail<AppDbContext, Program>(connectionString);
98+
builder.AddPostgresContextWithAuditTrail<AppDbContext>(connectionString, npgsql => { ... });
99+
```
100+
101+
### With pooling and audit trail
102+
103+
```csharp
104+
builder.AddPostgresContextPoolWithAuditTrail<AppDbContext>(connectionString);
105+
builder.AddPostgresContextPoolWithAuditTrail<AppDbContext>(connectionString, "MyApp.Migrations");
106+
builder.AddPostgresContextPoolWithAuditTrail<AppDbContext, Program>(connectionString);
107+
builder.AddPostgresContextPoolWithAuditTrail<AppDbContext>(connectionString, npgsql => { ... });
108+
```
109+
110+
---
111+
112+
## Migrations
113+
114+
Apply pending migrations at startup:
115+
116+
```csharp
117+
// Synchronous
118+
app.MigrateDatabase<AppDbContext>();
119+
120+
// Asynchronous
121+
await app.MigrateDatabaseAsync<AppDbContext>(ct);
122+
```
123+
124+
Both create a scoped service provider, resolve the context, and call `Database.Migrate` / `Database.MigrateAsync`.
125+
Place these calls after `app.Build()` and before `app.Run()`.
126+
127+
---
128+
129+
## Model configuration helpers
130+
131+
Add to `ConfigureConventions` and `OnModelCreating` in your DbContext:
132+
133+
```csharp
134+
protected override void ConfigureConventions(ModelConfigurationBuilder builder)
135+
{
136+
// Map all decimal properties to NUMERIC(40, 20) — prevents precision loss
137+
builder.ConfigureDecimalType();
138+
}
139+
140+
protected override void OnModelCreating(ModelBuilder modelBuilder)
141+
{
142+
// Set all foreign key delete behavior to Restrict (no accidental cascades)
143+
modelBuilder.RestrictFkDeleteBehaviorByDefault();
144+
}
145+
```
146+
147+
`ConfigureDecimalType` sets precision `(40, 20)` globally. Override individual properties via `[Precision]` or fluent
148+
API if you need a narrower type for a specific column.
149+
150+
`RestrictFkDeleteBehaviorByDefault` iterates all foreign keys at model build time and sets `DeleteBehavior.Restrict`.
151+
Override individual relationships fluently after this call if cascade delete is intentionally needed.
152+
153+
---
154+
155+
## Health checks
156+
157+
The health check is registered automatically by every `AddPostgresContext*` overload. It uses
158+
`AspNetCore.HealthChecks.NpgSql` with a 5-second timeout and is named `postgres_{DatabaseName}` where the database
159+
name is parsed from the connection string.
160+
161+
To expose the health check endpoint, use `MapHealthCheckEndpoints()` from `Pandatech.SharedKernel`:
162+
163+
```csharp
164+
app.MapHealthCheckEndpoints(); // /above-board/health
165+
```
166+
167+
Or register your own endpoint:
168+
169+
```csharp
170+
app.MapHealthChecks("/health");
171+
```
172+
173+
If the database name cannot be parsed from the connection string, registration throws `ArgumentException` at startup
174+
rather than silently registering a misnamed check.
175+
176+
---
177+
178+
## License
179+
180+
MIT

Readme.md

Lines changed: 0 additions & 98 deletions
This file was deleted.

0 commit comments

Comments
 (0)