use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub(crate) enum CursorCandidateReason {
NameSuggestsUpdated,
NameSuggestsCreated,
TimestampType,
IntegerMonotonic,
PrimaryKey,
Nullable,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) struct CursorCandidate {
pub column: String,
pub data_type: String,
pub is_nullable: bool,
pub is_primary_key: bool,
pub score: i32,
pub reasons: Vec<CursorCandidateReason>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) struct ChunkCandidate {
pub column: String,
pub data_type: String,
pub is_primary_key: bool,
pub score: i32,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) struct TableDiscovery {
pub schema: String,
pub table: String,
pub row_estimate: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub total_bytes: Option<i64>,
pub suggested_mode: String,
pub cursor_candidates: Vec<CursorCandidate>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub suggested_cursor_fallback_column: Option<String>,
pub chunk_candidates: Vec<ChunkCandidate>,
pub notes: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) struct DiscoveryArtifact {
pub rivet_version: String,
pub source_type: String,
pub scope: String,
pub tables: Vec<TableDiscovery>,
}
impl DiscoveryArtifact {
pub fn to_json_pretty(&self) -> crate::error::Result<String> {
Ok(serde_json::to_string_pretty(self)?)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn json_round_trip_artifact() {
let a = DiscoveryArtifact {
rivet_version: "0.0.0-test".into(),
source_type: "postgres".into(),
scope: r#"schema "public" (1 object)"#.into(),
tables: vec![TableDiscovery {
schema: "public".into(),
table: "orders".into(),
row_estimate: 1000,
total_bytes: Some(4096),
suggested_mode: "incremental".into(),
cursor_candidates: vec![CursorCandidate {
column: "updated_at".into(),
data_type: "timestamp".into(),
is_nullable: false,
is_primary_key: false,
score: 120,
reasons: vec![
CursorCandidateReason::NameSuggestsUpdated,
CursorCandidateReason::TimestampType,
],
}],
suggested_cursor_fallback_column: None,
chunk_candidates: vec![],
notes: vec![],
}],
};
let j = a.to_json_pretty().unwrap();
let back: DiscoveryArtifact = serde_json::from_str(&j).unwrap();
assert_eq!(back, a);
}
}