Skip to main content

schema_core/config/
index_mapping.rs

1use serde::Serialize;
2
3use crate::common::{FieldName, IndexName};
4
5use super::{ContentHash, Mapping};
6
7/// A fully-resolved mapping for one index: every field typed and ready for a
8/// sink to translate into its native mapping format.
9///
10/// A source produces this from the [`IndexSchema`](super::IndexSchema) — using
11/// each field's explicit [`Mapping`] where one is given, and the database's own
12/// column types where it is not. The result has a
13/// concrete type for every field, which is what a sink needs to create the
14/// index up front rather than leaving the destination to guess.
15#[derive(Debug, Clone, Serialize)]
16pub struct IndexMapping {
17    /// The logical index name (the config key) — the pipeline's stable identity.
18    pub index: IndexName,
19    /// Hash of the parsed index schema. A sink that owns a physical index folds
20    /// this into the index's name (e.g. `users_3f2a1b9c`), so a structural
21    /// schema change yields a new name — a fresh index that is re-seeded rather
22    /// than written into the old shape.
23    pub hash: ContentHash,
24    pub fields: Vec<ResolvedField>,
25}
26
27/// One field within an [`IndexMapping`]: the document key it lands under, its
28/// resolved [`Mapping`] (the `mapping_type` is always present), whether the
29/// value can be null, and the fields nested under it for `object` / `nested`
30/// types.
31#[derive(Debug, Clone, Serialize)]
32pub struct ResolvedField {
33    pub name: FieldName,
34    pub mapping: Mapping,
35    /// Whether this field's value can be null in the document. Derived by the
36    /// source while resolving the mapping — the config does not state it, but the
37    /// source knows (a column's `NOT NULL`, a primary key, a `default`, the
38    /// arity of a relation, an aggregate's zero-row behavior). A sink ignores it;
39    /// it exists for consumers that turn the mapping into typed bindings, where
40    /// `nullable` is the difference between `T` and `Option<T>`.
41    pub nullable: bool,
42    #[serde(skip_serializing_if = "Vec::is_empty")]
43    pub children: Vec<ResolvedField>,
44}