Skip to main content

timestamp_duration/
timestamp_duration.rs

1//! Validate fields with `format: date-time` and `format: duration`.
2//!
3//! Run with: `cargo run --example timestamp_duration --features validation`
4
5use kube_cel::{compile_schema, validate, validate_compiled};
6use serde_json::json;
7
8fn main() {
9    // Schema with date-time and duration formats
10    let schema = json!({
11        "type": "object",
12        "properties": {
13            "spec": {
14                "type": "object",
15                "properties": {
16                    "expiresAt": {
17                        "type": "string",
18                        "format": "date-time"
19                    },
20                    "timeout": {
21                        "type": "string",
22                        "format": "duration"
23                    }
24                },
25                "x-kubernetes-validations": [
26                    {
27                        "rule": "self.expiresAt > timestamp('2024-01-01T00:00:00Z')",
28                        "message": "must expire after 2024-01-01"
29                    },
30                    {
31                        "rule": "self.timeout <= duration('1h')",
32                        "message": "timeout must be at most 1 hour"
33                    }
34                ]
35            }
36        }
37    });
38
39    // ── Schema-based validation ──────────────────────────────────────
40
41    println!("=== Schema-based validation ===\n");
42
43    let valid = json!({
44        "spec": {
45            "expiresAt": "2025-06-15T12:00:00Z",
46            "timeout": "30m"
47        }
48    });
49    let errors = validate(&schema, &valid, None);
50    println!("Valid object: {} errors", errors.len());
51
52    let invalid = json!({
53        "spec": {
54            "expiresAt": "2023-06-15T12:00:00Z",
55            "timeout": "2h"
56        }
57    });
58    let errors = validate(&schema, &invalid, None);
59    println!("Invalid object: {} errors", errors.len());
60    for err in &errors {
61        println!("  [{path}] {msg}", path = err.field_path, msg = err.message);
62    }
63
64    // ── Compiled schema (pre-compile once, validate many) ────────────
65
66    println!("\n=== Compiled schema validation ===\n");
67
68    let compiled = compile_schema(&schema);
69
70    let objects = [
71        json!({"spec": {"expiresAt": "2025-01-01T00:00:00Z", "timeout": "30s"}}),
72        json!({"spec": {"expiresAt": "2023-12-31T23:59:59Z", "timeout": "45m"}}),
73        json!({"spec": {"expiresAt": "2025-06-15T00:00:00Z", "timeout": "90m"}}),
74    ];
75
76    for (i, obj) in objects.iter().enumerate() {
77        let errors = validate_compiled(&compiled, obj, None);
78        if errors.is_empty() {
79            println!("Object {i}: OK");
80        } else {
81            println!("Object {i}: {} error(s)", errors.len());
82            for err in &errors {
83                println!("  [{path}] {msg}", path = err.field_path, msg = err.message);
84            }
85        }
86    }
87
88    // ── Transition rule with timestamps ──────────────────────────────
89
90    println!("\n=== Transition rule (expiration cannot move earlier) ===\n");
91
92    let transition_schema = json!({
93        "type": "object",
94        "properties": {
95            "expiresAt": {
96                "type": "string",
97                "format": "date-time"
98            }
99        },
100        "x-kubernetes-validations": [{
101            "rule": "self.expiresAt >= oldSelf.expiresAt",
102            "message": "expiration cannot be moved earlier"
103        }]
104    });
105
106    let new_obj = json!({"expiresAt": "2025-12-01T00:00:00Z"});
107    let old_obj = json!({"expiresAt": "2025-06-01T00:00:00Z"});
108
109    let errors = validate(&transition_schema, &new_obj, Some(&old_obj));
110    println!("Extend expiration: {} errors", errors.len());
111
112    let bad_obj = json!({"expiresAt": "2025-01-01T00:00:00Z"});
113    let errors = validate(&transition_schema, &bad_obj, Some(&old_obj));
114    println!("Shorten expiration: {} errors", errors.len());
115    for err in &errors {
116        println!("  {err}");
117    }
118}