Skip to content

Commit 97525ad

Browse files
authored
Add copilot instructions (#3761)
1 parent 1d86399 commit 97525ad

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

.github/copilot-instructions.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Copilot Instructions for Npgsql EF Core Provider (EFCore.PG)
2+
3+
This is the PostgreSQL provider for [Entity Framework Core](https://github.com/dotnet/efcore), built on top of [Npgsql](https://github.com/npgsql/npgsql). It translates EF Core LINQ queries into PostgreSQL SQL and handles PostgreSQL-specific features like arrays, JSON, ranges, full-text search, NodaTime, and PostGIS/NetTopologySuite.
4+
5+
## Build and Test
6+
7+
```bash
8+
# Build
9+
dotnet build
10+
11+
# Run all tests (requires PostgreSQL - see "Test Database" below)
12+
dotnet test
13+
14+
# Run a specific test project
15+
dotnet test test/EFCore.PG.FunctionalTests
16+
dotnet test test/EFCore.PG.Tests
17+
18+
# Run a single test class
19+
dotnet test test/EFCore.PG.FunctionalTests --filter FullyQualifiedName~NorthwindSelectQueryNpgsqlTest
20+
21+
# Run a single test method
22+
dotnet test test/EFCore.PG.FunctionalTests --filter "FullyQualifiedName~NorthwindSelectQueryNpgsqlTest.Select_bool_closure"
23+
```
24+
25+
### Test Database
26+
27+
Tests auto-start a PostgreSQL testcontainer if no connection string is configured. To use an existing PostgreSQL instance, set the environment variable:
28+
29+
```bash
30+
export Test__Npgsql__DefaultConnection="Server=localhost;Username=npgsql_tests;Password=npgsql_tests"
31+
```
32+
33+
Some tests require PostGIS. Set `NPGSQL_TEST_POSTGIS=true` to enforce PostGIS availability (tests fail instead of skip if PostGIS is missing).
34+
35+
## Architecture
36+
37+
### Source Projects (src/)
38+
39+
- **EFCore.PG**: Main PostgreSQL provider. Contains query translation, type mappings, migrations, scaffolding, and service registration.
40+
- **EFCore.PG.NodaTime**: Plugin for NodaTime date/time types.
41+
- **EFCore.PG.NTS**: Plugin for PostGIS spatial types via NetTopologySuite.
42+
- **Shared/**: Utility code shared across all source projects via `<Compile Include>`.
43+
44+
### Test Projects (test/)
45+
46+
- **EFCore.PG.FunctionalTests**: Integration tests requiring a PostgreSQL database. Inherits extensively from EF Core's `Relational.Specification.Tests` base classes.
47+
- **EFCore.PG.Tests**: Unit tests that don't require a database.
48+
49+
### Key Source Directories (under src/EFCore.PG/)
50+
51+
- **Query/ExpressionTranslators/Internal/**: LINQ-to-SQL method/member translators (e.g. `NpgsqlStringMethodTranslator`, `NpgsqlArrayMethodTranslator`). Each translates .NET method calls into PostgreSQL SQL expressions.
52+
- **Query/Expressions/Internal/**: Custom PostgreSQL SQL expression nodes (`PgArrayIndexExpression`, `PgJsonTraversalExpression`, `PgRegexMatchExpression`, `PgILikeExpression`, `PgAnyExpression`, `PgUnnestExpression`, etc.).
53+
- **Query/Internal/**: Query pipeline components — SQL generation (`NpgsqlQuerySqlGenerator`), translation visitors, postprocessors.
54+
- **Storage/Internal/**: Type mapping between .NET types and PostgreSQL types (e.g. `NpgsqlStringTypeMapping`). Each mapping stores an `NpgsqlDbType` and configures `NpgsqlParameter` at execution time.
55+
- **Migrations/**: Migration SQL generation, including PostgreSQL-specific DDL (extensions, enums, sequences).
56+
- **Extensions/**: Extension methods for configuring the provider (`UseNpgsql()`) and PostgreSQL-specific model building (e.g. `HasPostgresExtension()`, `HasPostgresEnum()`).
57+
58+
### Plugin Architecture
59+
60+
NodaTime and NTS plugins hook into the main provider via EF Core's plugin interfaces (`IMethodCallTranslatorPlugin`, `IMemberTranslatorPlugin`, `IRelationalTypeMappingSourcePlugin`, etc.) registered through DI. This allows extending translations and type mappings without modifying the core provider.
61+
62+
## Test Patterns
63+
64+
### Inherited Specification Tests
65+
66+
Most functional tests inherit from EF Core base test classes and override methods to add PostgreSQL-specific SQL assertions:
67+
68+
```csharp
69+
public class NorthwindSelectQueryNpgsqlTest : NorthwindSelectQueryRelationalTestBase<NorthwindQueryNpgsqlFixture<NoopModelCustomizer>>
70+
{
71+
public override async Task Select_bool_closure(bool async)
72+
{
73+
await base.Select_bool_closure(async);
74+
75+
AssertSql(
76+
"""
77+
SELECT c."CustomerID", c."Address", ...
78+
FROM "Customers" AS c
79+
""");
80+
}
81+
}
82+
```
83+
84+
* All inherited query tests systematically override all methods in the EF-provided base class, in order to call `AssertSql()` to assert on the exact generated SQL. Always do this when e.g. inheriting a new EF functional test class.
85+
* Such test overrides must be placed in the same position in the file as its base test method in EF, to maintain consistency between EF and EFCore.PG. To do that, check the source for the base test class in the EF repo (https://github.com/dotnet/efcore); note that you may need to consult a specific commit in the EF repo that corresponds to what EFCore.PG is referencing.
86+
* EF query test contains a built-in ability to rewrite the SQL inside `AssertSql()` calls to whatever the provider currently emits; to trigger this, set the `EF_TEST_REWRITE_BASELINES` env var to `1` and run any test(s) - this will modify the source code. You can then inspect the change to confirm that it makes sense, etc.
87+
88+
### Conditional Execution
89+
90+
- `[MinimumPostgresVersion(major, minor)]`: Skips test if PostgreSQL version is too low.
91+
- `[RequiresPostgis]`: Skips test if PostGIS extension is unavailable.
92+
93+
## Conventions
94+
95+
- Targets the latest .NET (currently `net11.0`) with C# `latest` language version. Nullable reference types are enabled. Warnings are treated as errors.
96+
- Prefer `var` everywhere, but prefer collection expressions even more (which require the type on the left-hand side).
97+
- Expression-bodied members are preferred for properties, indexers, and accessors.
98+
- Switch expressions are used whenever possible. When not possible, switch statements are always preferable to if condition chains.
99+
- Primary constructors are used whenever possible.
100+
- Private fields use `_camelCase`; parameters/locals use `camelCase`; types/methods/properties use `PascalCase`.
101+
- PostgreSQL-specific SQL expression classes are prefixed with `Pg` (e.g. `PgArrayIndexExpression`, `PgBinaryExpression`).
102+
- Services are registered via `TryAdd` in `EntityFrameworkNpgsqlServicesBuilder` to allow user overrides.
103+
- Global implicit usings are configured in `Directory.Build.props` for common EF Core and Npgsql namespaces — these do not need to be repeated in individual files.
104+
- The functional test project uses `RootNamespace: Microsoft.EntityFrameworkCore` to align with EF Core's specification test base classes.

0 commit comments

Comments
 (0)