Skip to main content

force_sync/store/pg/
conflict.rs

1//! Conflict repository helpers for the `PostgreSQL` sync store.
2
3use serde_json::Value;
4use tokio_postgres::GenericClient;
5
6use crate::error::ForceSyncError;
7
8use super::PgStore;
9
10/// Conflict record stored for later review.
11#[allow(clippy::derive_partial_eq_without_eq)]
12#[derive(Debug, Clone, PartialEq)]
13pub struct SyncConflict {
14    /// Tenant identifier.
15    pub tenant: String,
16    /// Salesforce object name.
17    pub object_name: String,
18    /// Canonical external ID.
19    pub external_id: String,
20    /// Field that conflicted.
21    pub field_name: String,
22    /// Left-hand value.
23    pub left_value: Value,
24    /// Right-hand value.
25    pub right_value: Value,
26    /// Conflict resolution policy or outcome.
27    pub resolution: Option<String>,
28}
29
30async fn insert_conflict_query<C>(
31    client: &C,
32    conflict: &SyncConflict,
33) -> Result<i64, ForceSyncError>
34where
35    C: GenericClient + Sync + ?Sized,
36{
37    let row = client
38        .query_one(
39            "insert into sync_conflict (
40                tenant,
41                object_name,
42                external_id,
43                field_name,
44                left_value,
45                right_value,
46                resolution
47            ) values ($1, $2, $3, $4, $5::jsonb, $6::jsonb, $7)
48            returning conflict_id",
49            &[
50                &conflict.tenant,
51                &conflict.object_name,
52                &conflict.external_id,
53                &conflict.field_name,
54                &conflict.left_value,
55                &conflict.right_value,
56                &conflict.resolution,
57            ],
58        )
59        .await?;
60
61    Ok(row.get(0))
62}
63
64impl PgStore {
65    /// Inserts a conflict row and returns its database identifier.
66    ///
67    /// # Errors
68    ///
69    /// Returns an error if the database write fails.
70    pub async fn insert_conflict(&self, conflict: &SyncConflict) -> Result<i64, ForceSyncError> {
71        let client = self.pool().get().await?;
72        insert_conflict_query(&**client, conflict).await
73    }
74}