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