Skip to main content

cell_model/
schema.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2025 Leif Rydenfalk – https://github.com/Leif-Rydenfalk/cell
3
4//! Schema Registry Types
5//!
6//! This module provides the foundation for a robust, versioned schema system
7//! that enables compile-time type sharing between cells.
8
9use alloc::string::String;
10use alloc::vec::Vec;
11use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
12use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
13
14/// A versioned schema entry in the registry.
15#[derive(
16    Archive,
17    RkyvSerialize,
18    RkyvDeserialize,
19    SerdeSerialize,
20    SerdeDeserialize,
21    Debug,
22    Clone,
23    PartialEq,
24)]
25#[archive(check_bytes)]
26pub struct SchemaEntry {
27    /// Schema name (usually the struct name)
28    pub name: String,
29
30    /// Semantic version of the schema
31    pub version: SchemaVersion,
32
33    /// Field definitions
34    pub fields: Vec<FieldDef>,
35
36    /// Additional metadata (documentation, constraints, etc.)
37    pub metadata: SchemaMetadata,
38
39    /// Hash of the source code that generated this schema
40    pub source_hash: String,
41}
42
43/// Semantic versioning for schemas.
44#[derive(
45    Archive,
46    RkyvSerialize,
47    RkyvDeserialize,
48    SerdeSerialize,
49    SerdeDeserialize,
50    Debug,
51    Clone,
52    PartialEq,
53    Eq,
54    PartialOrd,
55    Ord,
56)]
57#[archive(check_bytes)]
58pub struct SchemaVersion {
59    pub major: u16,
60    pub minor: u16,
61    pub patch: u16,
62}
63
64impl SchemaVersion {
65    pub fn new(major: u16, minor: u16, patch: u16) -> Self {
66        Self {
67            major,
68            minor,
69            patch,
70        }
71    }
72
73    /// Check if this version is compatible with another (same major)
74    pub fn compatible_with(&self, other: &SchemaVersion) -> bool {
75        self.major == other.major
76    }
77}
78
79/// Field definition in a schema.
80#[derive(
81    Archive,
82    RkyvSerialize,
83    RkyvDeserialize,
84    SerdeSerialize,
85    SerdeDeserialize,
86    Debug,
87    Clone,
88    PartialEq,
89)]
90#[archive(check_bytes)]
91pub struct FieldDef {
92    pub name: String,
93    pub ty: String,              // Type as string (e.g., "u64", "String")
94    pub attributes: Vec<String>, // e.g., "primary_key", "indexed"
95    pub nullable: bool,
96    pub default_value: Option<String>,
97}
98
99/// Metadata for schema documentation and constraints.
100#[derive(
101    Archive,
102    RkyvSerialize,
103    RkyvDeserialize,
104    SerdeSerialize,
105    SerdeDeserialize,
106    Debug,
107    Clone,
108    PartialEq,
109    Default,
110)]
111#[archive(check_bytes)]
112pub struct SchemaMetadata {
113    pub description: Option<String>,
114    pub author: Option<String>,
115    pub created_at: Option<u64>, // Unix timestamp
116    pub updated_at: Option<u64>,
117    pub constraints: Vec<SchemaConstraint>,
118}
119
120/// Schema constraints for validation.
121#[derive(
122    Archive,
123    RkyvSerialize,
124    RkyvDeserialize,
125    SerdeSerialize,
126    SerdeDeserialize,
127    Debug,
128    Clone,
129    PartialEq,
130)]
131#[archive(check_bytes)]
132pub enum SchemaConstraint {
133    Unique {
134        fields: Vec<String>,
135    },
136    Index {
137        fields: Vec<String>,
138        name: String,
139    },
140    Check {
141        expression: String,
142    },
143    ForeignKey {
144        field: String,
145        references: String,
146        on_delete: ReferentialAction,
147    },
148}
149
150#[derive(
151    Archive,
152    RkyvSerialize,
153    RkyvDeserialize,
154    SerdeSerialize,
155    SerdeDeserialize,
156    Debug,
157    Clone,
158    PartialEq,
159)]
160#[archive(check_bytes)]
161pub enum ReferentialAction {
162    Cascade,
163    SetNull,
164    Restrict,
165    NoAction,
166}
167
168/// Registry operations for schema management.
169#[derive(
170    Archive, RkyvSerialize, RkyvDeserialize, SerdeSerialize, SerdeDeserialize, Debug, Clone,
171)]
172#[archive(check_bytes)]
173pub enum SchemaRegistryRequest {
174    /// Register a new schema (declaration)
175    Register { entry: SchemaEntry },
176
177    /// Retrieve a schema by name (consumption)
178    Get {
179        name: String,
180        version: Option<SchemaVersion>,
181    },
182
183    /// List all available schemas
184    List { prefix: Option<String> },
185
186    /// Check if schema exists and get compatibility info
187    Check {
188        name: String,
189        version: SchemaVersion,
190    },
191
192    /// Evolve an existing schema (migration)
193    Evolve {
194        name: String,
195        from_version: SchemaVersion,
196        to_entry: SchemaEntry,
197    },
198}
199
200#[derive(
201    Archive, RkyvSerialize, RkyvDeserialize, SerdeSerialize, SerdeDeserialize, Debug, Clone,
202)]
203#[archive(check_bytes)]
204pub enum SchemaRegistryResponse {
205    /// Schema registered successfully
206    Registered { version: SchemaVersion },
207
208    /// Schema retrieved
209    Found { entry: SchemaEntry },
210
211    /// Schema list
212    List { entries: Vec<SchemaEntry> },
213
214    /// Compatibility check result
215    Compatible {
216        current: SchemaVersion,
217        compatible: bool,
218        migration_required: bool,
219    },
220
221    /// Schema evolved
222    Evolved { new_version: SchemaVersion },
223
224    /// Error response
225    Error {
226        code: SchemaErrorCode,
227        message: String,
228    },
229}
230
231#[derive(
232    Archive,
233    RkyvSerialize,
234    RkyvDeserialize,
235    SerdeSerialize,
236    SerdeDeserialize,
237    Debug,
238    Clone,
239    Copy,
240    PartialEq,
241    Eq,
242)]
243#[archive(check_bytes)]
244pub enum SchemaErrorCode {
245    NotFound,
246    VersionMismatch,
247    IncompatibleChange,
248    InvalidField,
249    AlreadyExists,
250    InternalError,
251}