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    match validate(&schema, &valid, None) {
50        Ok(()) => println!("Valid object: OK"),
51        Err(errors) => println!("Valid object: {} errors", errors.len()),
52    }
53
54    let invalid = json!({
55        "spec": {
56            "expiresAt": "2023-06-15T12:00:00Z",
57            "timeout": "2h"
58        }
59    });
60    if let Err(errors) = validate(&schema, &invalid, None) {
61        println!("Invalid object: {} errors", errors.len());
62        for err in &errors {
63            println!("  [{path}] {msg}", path = err.field_path, msg = err.message);
64        }
65    }
66
67    // ── Compiled schema (pre-compile once, validate many) ────────────
68
69    println!("\n=== Compiled schema validation ===\n");
70
71    let compiled = compile_schema(&schema);
72
73    let objects = [
74        json!({"spec": {"expiresAt": "2025-01-01T00:00:00Z", "timeout": "30s"}}),
75        json!({"spec": {"expiresAt": "2023-12-31T23:59:59Z", "timeout": "45m"}}),
76        json!({"spec": {"expiresAt": "2025-06-15T00:00:00Z", "timeout": "90m"}}),
77    ];
78
79    for (i, obj) in objects.iter().enumerate() {
80        match validate_compiled(&compiled, obj, None) {
81            Ok(()) => println!("Object {i}: OK"),
82            Err(errors) => {
83                println!("Object {i}: {} error(s)", errors.len());
84                for err in &errors {
85                    println!("  [{path}] {msg}", path = err.field_path, msg = err.message);
86                }
87            }
88        }
89    }
90
91    // ── Transition rule with timestamps ──────────────────────────────
92
93    println!("\n=== Transition rule (expiration cannot move earlier) ===\n");
94
95    let transition_schema = json!({
96        "type": "object",
97        "properties": {
98            "expiresAt": {
99                "type": "string",
100                "format": "date-time"
101            }
102        },
103        "x-kubernetes-validations": [{
104            "rule": "self.expiresAt >= oldSelf.expiresAt",
105            "message": "expiration cannot be moved earlier"
106        }]
107    });
108
109    let new_obj = json!({"expiresAt": "2025-12-01T00:00:00Z"});
110    let old_obj = json!({"expiresAt": "2025-06-01T00:00:00Z"});
111
112    match validate(&transition_schema, &new_obj, Some(&old_obj)) {
113        Ok(()) => println!("Extend expiration: OK"),
114        Err(errors) => println!("Extend expiration: {} errors", errors.len()),
115    }
116
117    let bad_obj = json!({"expiresAt": "2025-01-01T00:00:00Z"});
118    if let Err(errors) = validate(&transition_schema, &bad_obj, Some(&old_obj)) {
119        println!("Shorten expiration: {} errors", errors.len());
120        for err in &errors {
121            println!("  {err}");
122        }
123    }
124}