(doc) : ajout et modification de docs après arbitrage

This commit is contained in:
jpgiannetti
2026-01-31 21:09:59 +01:00
parent f99fb3c614
commit 841028d1b2
24 changed files with 3081 additions and 301 deletions

View File

@@ -49,9 +49,163 @@ sqlc generate
contents, err := q.GetContentNearby(ctx, location, radius, limit)
```
## Gestion des Types PostGIS
**Problème** : sqlc génère du code depuis SQL, mais les types PostGIS (`geography`, `geometry`) ne mappent pas naturellement en Go → types opaques (`[]byte`, `interface{}`), perte de type safety.
### Solution : Wrappers Typés + Fonctions de Conversion
**Architecture** :
```
SQL (PostGIS)
↓ ST_AsGeoJSON() / ST_AsText() / pgtype.Point
Code Go (wrapper types)
Business Logic (strongly-typed)
```
**Implémentation** :
```go
// backend/internal/geo/types.go
package geo
import (
"database/sql/driver"
"encoding/json"
"github.com/jackc/pgx/v5/pgtype"
)
// GeoJSON représente un point géographique en format JSON
type GeoJSON struct {
Type string `json:"type"` // "Point"
Coordinates [2]float64 `json:"coordinates"` // [lon, lat]
}
// Value() et Scan() implémentent sql.Valuer et sql.Scanner
// pour conversion automatique avec sqlc
func (g GeoJSON) Value() (driver.Value, error) {
return json.Marshal(g)
}
func (g *GeoJSON) Scan(value interface{}) error {
bytes, _ := value.([]byte)
return json.Unmarshal(bytes, g)
}
// Distance calcule la distance entre 2 points (Haversine)
func (g GeoJSON) Distance(other GeoJSON) float64 {
// Implémentation Haversine formula
// ...
}
// WKT représente un point en Well-Known Text
type WKT string // "POINT(2.3522 48.8566)"
func (w WKT) Scan(value interface{}) error {
if str, ok := value.(string); ok {
*w = WKT(str)
}
return nil
}
```
### Patterns SQL Recommandés
**Pattern 1 : GeoJSON (recommandé pour frontend)**
```sql
-- queries/poi.sql
-- name: GetPOIsNearby :many
SELECT
id,
name,
ST_AsGeoJSON(location)::jsonb as location, -- ← Conversion en JSON
ST_Distance(location, $1::geography) as distance_meters
FROM points_of_interest
WHERE ST_DWithin(location, $1::geography, $2)
ORDER BY distance_meters
LIMIT $3;
```
```go
// Code généré par sqlc
type GetPOIsNearbyRow struct {
ID int64
Name string
Location json.RawMessage // ← Peut être parsé en GeoJSON
DistanceMeters float64
}
// Utilisation
rows, err := q.GetPOIsNearby(ctx, userLocation, radius, limit)
for _, row := range rows {
var poi geo.GeoJSON
json.Unmarshal(row.Location, &poi)
// poi est maintenant strongly-typed
}
```
**Pattern 2 : WKT (pour debug/logging)**
```sql
-- name: GetPOILocation :one
SELECT
id,
ST_AsText(location) as location_wkt -- ← "POINT(2.3522 48.8566)"
FROM points_of_interest
WHERE id = $1;
```
**Pattern 3 : Utiliser pgtype pour types natifs**
```sql
-- name: GetDistanceBetweenPOIs :one
SELECT
ST_Distance(
(SELECT location FROM points_of_interest WHERE id = $1),
(SELECT location FROM points_of_interest WHERE id = $2)
)::float8 as distance_meters; -- ← Force conversion en float64
```
### Index PostGIS pour Performance
Créer un index GIST pour optimiser les requêtes ST_DWithin :
```sql
-- migrations/002_add_postgis_indexes.up.sql
CREATE INDEX idx_poi_location_gist
ON points_of_interest USING GIST(location);
CREATE INDEX idx_user_last_position_gist
ON user_locations USING GIST(last_position);
```
### Checklist d'Implémentation
- [ ] Créer package `backend/internal/geo/types.go` avec wrappers
- [ ] Implémenter `Scan/Value` pour conversion automatique
- [ ] Écrire requêtes SQL avec `ST_AsGeoJSON()` / `ST_AsText()`
- [ ] Ajouter index GIST sur colonnes géographiques
- [ ] Documenter patterns dans `backend/README.md`
- [ ] Tests d'intégration avec Testcontainers (PostGIS réel)
### Impact
-**Type safety** retrouvée : Plus de `interface{}` opaques
-**Performance** : Index GIST + conversion optimisée
-**Maintenabilité** : Patterns clairs, réutilisables
-**Complexité** : Une couche de plus, mais justifiée
**Référence** : Résout incohérence #4 dans [INCONSISTENCIES-ANALYSIS.md](../INCONSISTENCIES-ANALYSIS.md#4--orm-sqlc-vs-types-postgis)
## Conséquences
- Dépendance : `github.com/sqlc-dev/sqlc`
- Fichier `sqlc.yaml` à la racine pour configuration
- Migrations gérées séparément avec `golang-migrate`
- CI doit exécuter `sqlc generate` pour valider cohérence SQL/Go
**Librairies** : Voir [ADR-020](020-librairies-go.md) pour stack complet (sqlc + golang-migrate + pgx)