v0.5.3-pre.002
This commit is contained in:
@@ -1,90 +1,79 @@
|
||||
<!-- file: ks-store/USAGE.md -->
|
||||
<!-- version: 4 -->
|
||||
<!-- version: 5 -->
|
||||
|
||||
# Utilisation de ks-store
|
||||
|
||||
## Connexion PostgreSQL
|
||||
## Ouvrir le store
|
||||
|
||||
Le consommateur transmet uniquement le backend sélectionné et son objet d'options déjà résolu. Il ne construit jamais un pool PostgreSQL.
|
||||
|
||||
```rust
|
||||
let options = match ks_store::PostgresStoreOptions::new(
|
||||
database_url,
|
||||
10,
|
||||
10_000,
|
||||
let options = match ks_store::StoreOpenOptions::new(
|
||||
true,
|
||||
"postgres",
|
||||
serde_json::json!({
|
||||
"url": database_url,
|
||||
"max_connections": 10,
|
||||
"connect_timeout_ms": 10_000,
|
||||
"auto_initialize_schema": true
|
||||
}),
|
||||
) {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
|
||||
println!("postgres endpoint: {}", options.masked_dsn());
|
||||
|
||||
let store = match ks_store::PostgresStore::connect(options).await {
|
||||
let store = match ks_store::Store::open(options).await {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
```
|
||||
|
||||
`PostgresStoreOptions::new` valide le DSN, le nombre de connexions et le timeout. Lorsque `auto_initialize_schema` vaut `true`, la connexion applique les schémas idempotents. Utiliser `masked_dsn` ou `mask_postgres_dsn` dans les logs ; ne jamais journaliser le DSN brut.
|
||||
`Store::open` interprète les options du backend actif, crée la connexion, exécute l'auto-initialisation lorsqu'elle est configurée et capture un résumé d'initialisation sanitisé. PostgreSQL reste le seul backend opérationnel exigé en `0.5.3-pre.002`; un code backend inconnu est refusé proprement.
|
||||
|
||||
## Diagnostics
|
||||
## Résumés sûrs
|
||||
|
||||
```rust
|
||||
let health = store.health_snapshot().await;
|
||||
let migrations = store.migration_snapshot().await;
|
||||
let backend = store.backend_diagnostics().await;
|
||||
|
||||
println!("health={:?}", health.status);
|
||||
println!("migration={:?}", migrations.status);
|
||||
println!("backend={:?}", backend.descriptor.backend);
|
||||
```
|
||||
|
||||
Les diagnostics de tables raw, Core et decode/materialization sont également disponibles par les méthodes `*_table_diagnostics`.
|
||||
|
||||
```rust
|
||||
let raw_tables = match store.raw_table_diagnostics().await {
|
||||
let configuration = store.configuration_summary();
|
||||
let initialization = store.initialization_summary();
|
||||
let runtime = match store.runtime_summary().await {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
```
|
||||
|
||||
for table in raw_tables {
|
||||
Ces contrats ne contiennent pas les options backend brutes. Le descripteur de connexion éventuellement exposé par `runtime.backend` est masqué par le backend propriétaire.
|
||||
|
||||
Le résumé d'initialisation classe les ressources par modèles logiques et fournit des compteurs. Il expose aussi `objects`, une liste de catégories physiques sans noms d'objets : PostgreSQL publie déjà le total `table`, tandis que `pre.003` ajoutera le total `index` avec le nouveau baseline. Les noms physiques de tables, index et contraintes restent internes au backend.
|
||||
|
||||
## Diagnostics de ressources
|
||||
|
||||
```rust
|
||||
let raw_resources = match store.raw_resource_diagnostics().await {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
for resource in raw_resources {
|
||||
println!(
|
||||
"table={} domain={} exists={}",
|
||||
table.table_name,
|
||||
table.domain,
|
||||
table.exists
|
||||
"resource={} model={} available={}",
|
||||
resource.resource_code,
|
||||
resource.model_code,
|
||||
resource.available
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Pagination bornée
|
||||
|
||||
```rust
|
||||
let first_page = ks_store::PageRequest::first_page();
|
||||
|
||||
let next_page = match ks_store::PageRequest::new(250, 250) {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
|
||||
assert_eq!(first_page.limit, ks_store::DEFAULT_PAGE_SIZE);
|
||||
assert!(next_page.limit <= ks_store::MAX_PAGE_SIZE);
|
||||
```
|
||||
Les méthodes `core_resource_diagnostics`, `decode_resource_diagnostics` et `known_resource_diagnostics` suivent le même contrat backend-agnostique.
|
||||
|
||||
## Contrats de repositories
|
||||
|
||||
Les traits publics principaux sont :
|
||||
Les traits publics effectivement implémentés sont :
|
||||
|
||||
- `StoreHealthStore` ;
|
||||
- `RawTransactionStore` ;
|
||||
- `CoreTransactionStore` ;
|
||||
- `CoreExtractionStore` ;
|
||||
- `DecodePipelineStore` ;
|
||||
- `ProgramObservationStore` ;
|
||||
- `DecodedEventStore` ;
|
||||
- `MaterializedEventStore` ;
|
||||
- `ProcessingLedgerStore`.
|
||||
- `DecodePipelineStore`.
|
||||
|
||||
Ils permettent au pipeline de dépendre d’un contrat async plutôt que d’une requête SQL directe.
|
||||
`Store` implémente ces traits et délègue au backend privé. Les anciens traits historiques sans implémentation réelle ont été retirés avant gel de l'API.
|
||||
|
||||
## Replay et requêtes bornées
|
||||
|
||||
@@ -93,71 +82,43 @@ let candidates = match store.replay_transaction_candidates(filter).await {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
|
||||
for candidate in candidates {
|
||||
println!(
|
||||
"signature={} slot={}",
|
||||
candidate.signature,
|
||||
candidate.slot
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```rust
|
||||
let programs = match store.replay_program_summaries(program_filter).await {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
|
||||
let entities = match store.replay_entity_summaries(entity_filter).await {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
|
||||
println!("programs={}, entities={}", programs.len(), entities.len());
|
||||
```
|
||||
|
||||
Les filtres refusent les limites nulles ou supérieures aux bornes publiques. `PageRequest` impose également `DEFAULT_PAGE_SIZE` et `MAX_PAGE_SIZE`.
|
||||
Les contrats publics utilisent `ReplayTransaction*`, `ReplayProgram*` et `ReplayEntity*`. Le scope d'instruction utilise désormais `TopLevel`, `Inner` et `Logs`; le terme historique `outer` n'est pas introduit dans la nouvelle API.
|
||||
|
||||
## Pagination bornée
|
||||
|
||||
```rust
|
||||
let first_page = ks_store::PageRequest::first_page();
|
||||
let next_page = match ks_store::PageRequest::new(250, 250) {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
assert_eq!(first_page.limit, ks_store::DEFAULT_PAGE_SIZE);
|
||||
assert!(next_page.limit <= ks_store::MAX_PAGE_SIZE);
|
||||
```
|
||||
|
||||
La refonte cursorisée prévue par le plan `0.5.3` reste dans la tranche repositories/replay ultérieure.
|
||||
|
||||
## Transactions atomiques
|
||||
|
||||
Les bundles `CoreExtractionBundle`, `DecodePersistenceBundle` et `MaterializationPersistenceBundle` regroupent les écritures qui doivent réussir ou être annulées ensemble. Les consommateurs ne doivent pas reproduire manuellement ces transactions avec des écritures isolées.
|
||||
Les bundles `CoreExtractionBundle`, `DecodePersistenceBundle` et `MaterializationPersistenceBundle` regroupent les écritures qui doivent réussir ou être annulées ensemble. Les consommateurs ne doivent pas reproduire manuellement ces transactions avec des écritures SQL isolées.
|
||||
|
||||
## Validation des noms de tables
|
||||
## Tests PostgreSQL réels
|
||||
|
||||
```rust
|
||||
if let Err(error) = ks_store::validate_raw_store_table_names() {
|
||||
return Err(error);
|
||||
}
|
||||
if let Err(error) = ks_store::validate_core_store_table_names() {
|
||||
return Err(error);
|
||||
}
|
||||
if let Err(error) = ks_store::validate_decode_store_table_names() {
|
||||
return Err(error);
|
||||
}
|
||||
Les tests opt-in utilisent `KS_SECRET_POSTGRES_TEST_URL`. Aucun credential réel ne doit être enregistré dans les fixtures ou logs. Les erreurs d'ouverture de connexion sont volontairement sanitisées.
|
||||
|
||||
assert!(ks_store::is_valid_solana_table_name(
|
||||
ks_store::CORE_TRANSACTIONS_TABLE_NAME
|
||||
));
|
||||
```
|
||||
## Limites de `pre.002`
|
||||
|
||||
## Schéma et tables
|
||||
|
||||
Les constantes `RAW_STORE_TABLE_NAMES`, `CORE_STORE_TABLE_NAMES` et `DECODE_STORE_TABLE_NAMES` exposent les noms canoniques. Les fonctions `validate_*_table_names` et `is_valid_solana_table_name` servent aux audits et outils d’administration.
|
||||
|
||||
## Erreurs et invariants
|
||||
|
||||
Toutes les APIs utilisent `ks_core::Result`. Les DTO valident notamment les signatures, chemins, Program IDs, clés, montants, états de traitement et identités de ledger. Les erreurs de contrat peuvent être construites avec `storage_contract_error`.
|
||||
|
||||
## Tests instructifs
|
||||
|
||||
- les tests `*_rejects_*` documentent les invariants des DTO et filtres ;
|
||||
- `decoded_events_and_ledger_roll_back_together` vérifie l’atomicité ;
|
||||
- `optional_postgres_*_from_env` couvre les parcours réels lorsque l’environnement PostgreSQL est configuré ;
|
||||
- les tests de schéma vérifient les noms, index, contraintes et migrations.
|
||||
|
||||
## Limites
|
||||
|
||||
- backend actif : PostgreSQL ;
|
||||
- les tests réels sont optionnels sans DSN de test ;
|
||||
- la crate ne prend aucune décision de décodage ou de matérialisation.
|
||||
- les tables restent temporairement sous leur namespace historique jusqu'à `pre.003` ;
|
||||
- les migrations PostgreSQL ne sont pas encore déplacées sous `migrations/postgres/` ;
|
||||
- la pagination cursorisée et l'invalidation descendante sont traitées dans la tranche repositories/replay ;
|
||||
- la refonte complète des fenêtres desktop `demo_store_*` est prévue dans la tranche consommateurs.
|
||||
|
||||
Reference in New Issue
Block a user