schema_core/config.rs
1mod aggregate;
2mod content_hash;
3mod field;
4mod filter;
5mod flusso_type;
6mod index_mapping;
7mod join;
8mod projection;
9mod schema;
10mod secret;
11mod sink;
12mod soft_delete;
13mod transform;
14
15pub use aggregate::*;
16pub use content_hash::*;
17pub use field::*;
18pub use filter::*;
19pub use flusso_type::*;
20pub use index_mapping::*;
21pub use join::*;
22pub use schema::*;
23pub use secret::*;
24pub use sink::*;
25pub use soft_delete::*;
26pub use transform::*;
27
28use serde::{Deserialize, Serialize};
29
30use crate::common;
31
32/// What the pipeline does when a sink **rejects a document at the item level** —
33/// it accepted the batch but refused a specific document (a mapping conflict, a
34/// malformed value). Distinct from a flush-wide failure, which always stops the
35/// run. Set globally on the config and overridable per index (both live in the
36/// `schema` crate's `Config`/`Index`, which assemble this policy).
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
38#[serde(rename_all = "snake_case")]
39pub enum FailurePolicy {
40 /// Stop the run on the first rejected document. The batch is left
41 /// unconfirmed and redelivered on restart, so a persistently-bad document
42 /// halts sync until the data is fixed or the policy is changed. The default,
43 /// because dropping data should be opt-in.
44 #[default]
45 Stop,
46 /// Quarantine each rejected document (surfaced via metrics/status and logs)
47 /// and continue: the rest of the batch is applied, the slot advances, and
48 /// the poison is not redelivered — it simply never lands until its source
49 /// row changes again.
50 Skip,
51}
52
53/// The shape of a single search document: a root table and the fields built
54/// from its columns and related tables.
55#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
56pub struct IndexSchema {
57 pub version: u8,
58 pub table: common::TableName,
59 pub db_schema: DatabaseSchema,
60 #[serde(default, skip_serializing_if = "Option::is_none")]
61 pub primary_key: Option<common::ColumnName>,
62 /// Reserved: the column whose value would become the document `_id`.
63 /// Not honored yet — the schema layer rejects a set `doc_id`, so this is
64 /// always `None`; the `_id` is derived from [`primary_key`](Self::primary_key).
65 #[serde(default, skip_serializing_if = "Option::is_none")]
66 pub doc_id: Option<common::ColumnName>,
67 #[serde(default, skip_serializing_if = "Option::is_none")]
68 pub soft_delete: Option<SoftDelete>,
69 /// Root filters: only root rows matching every filter become documents.
70 /// A row that stops matching emits a tombstone, exactly like
71 /// [`soft_delete`](Self::soft_delete) — both fold into the document
72 /// query's `WHERE`, so "no row came back" means "this document should not
73 /// exist".
74 #[serde(default, skip_serializing_if = "Option::is_none")]
75 pub filters: Option<Vec<Filter>>,
76 pub fields: Vec<Field>,
77}