1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
//! Doctests for ToSchema derive macro
/// ```
/// # use buoyant_kernel as delta_kernel;
/// # use delta_kernel_derive::ToSchema;
/// #[derive(ToSchema)]
/// pub struct WithFields {
/// some_name: String,
/// }
/// ```
;
/// ```compile_fail
/// # use buoyant_kernel as delta_kernel;
/// # use delta_kernel_derive::ToSchema;
/// #[derive(ToSchema)]
/// pub struct NoFields;
/// ```
;
/// ```
/// # use buoyant_kernel as delta_kernel;
/// # use delta_kernel_derive::ToSchema;
/// # use std::collections::HashMap;
/// #[derive(ToSchema)]
/// pub struct WithAngleBracketPath {
/// map_field: HashMap<String, String>,
/// }
/// ```
;
/// ```
/// # use buoyant_kernel as delta_kernel;
/// # use delta_kernel_derive::ToSchema;
/// # use std::collections::HashMap;
/// #[derive(ToSchema)]
/// pub struct WithAttributedField {
/// #[allow_null_container_values]
/// map_field: HashMap<String, String>,
/// }
/// ```
;
/// ```compile_fail
/// # use buoyant_kernel as delta_kernel;
/// # use delta_kernel_derive::ToSchema;
/// #[derive(ToSchema)]
/// pub struct WithInvalidAttributeTarget {
/// #[allow_null_container_values]
/// some_name: String,
/// }
/// ```
;
/// Verify that `#[allow_null_container_values]` works on `Option<HashMap<_, _>>` fields.
/// This is needed for optional map fields like `Remove.partition_values` that can contain
/// null values.
/// ```
/// # use buoyant_kernel as delta_kernel;
/// # use delta_kernel_derive::ToSchema;
/// # use std::collections::HashMap;
/// #[derive(ToSchema)]
/// pub struct WithOptionalAttributedField {
/// #[allow_null_container_values]
/// map_field: Option<HashMap<String, String>>,
/// }
/// ```
;
/// Verify that `#[allow_null_container_values]` fails on `Option<_>` fields that are not maps.
/// ```compile_fail
/// # use buoyant_kernel as delta_kernel;
/// # use delta_kernel_derive::ToSchema;
/// #[derive(ToSchema)]
/// pub struct WithInvalidOptionalAttributeTarget {
/// #[allow_null_container_values]
/// some_name: Option<String>,
/// }
/// ```
;
/// ```compile_fail
/// # use buoyant_kernel as delta_kernel;
/// # use delta_kernel_derive::ToSchema;
/// # use syn::Token;
/// #[derive(ToSchema)]
/// pub struct WithInvalidFieldType {
/// token: Token![struct],
/// }
/// ```
;
/// Verify that `#[field_id]` / `#[nested_field_id]` on a list field produce the expected
/// `parquet.field.id` and `delta.columnMapping.nested.ids` metadata on the generated `StructField`.
/// ```
/// # use buoyant_kernel as delta_kernel;
/// # use delta_kernel_derive::ToSchema;
/// # use delta_kernel::schema::{ToSchema, ColumnMetadataKey, MetadataValue};
/// #[derive(ToSchema)]
/// pub struct WithFieldIds {
/// #[field_id = 132]
/// #[nested_field_id = 133]
/// split_offsets: Option<Vec<i64>>,
/// }
/// let schema = WithFieldIds::to_schema();
/// let field = schema.field("splitOffsets").unwrap();
/// assert_eq!(
/// field.metadata.get(ColumnMetadataKey::ParquetFieldId.as_ref()),
/// Some(&MetadataValue::Number(132)),
/// );
/// let nested = field
/// .metadata
/// .get(ColumnMetadataKey::ColumnMappingNestedIds.as_ref())
/// .unwrap();
/// assert_eq!(nested.to_string(), r#"{"splitOffsets.element":133}"#);
/// ```
;
/// Verify that `#[nested_field_id]` is rejected on a non-list field.
/// ```compile_fail
/// # use buoyant_kernel as delta_kernel;
/// # use delta_kernel_derive::ToSchema;
/// #[derive(ToSchema)]
/// pub struct WithNestedFieldIdOnScalar {
/// #[nested_field_id = 5]
/// some_name: String,
/// }
/// ```
;
/// Verify that an out-of-range `#[field_id]` (must be `1..=i32::MAX`) is rejected.
/// ```compile_fail
/// # use buoyant_kernel as delta_kernel;
/// # use delta_kernel_derive::ToSchema;
/// #[derive(ToSchema)]
/// pub struct WithOutOfRangeFieldId {
/// #[field_id = 9223372036854775807]
/// some_name: String,
/// }
/// ```
;
/// Verify that a malformed `#[field_id]` shape (bare path, no value) is rejected.
/// ```compile_fail
/// # use buoyant_kernel as delta_kernel;
/// # use delta_kernel_derive::ToSchema;
/// #[derive(ToSchema)]
/// pub struct WithMalformedFieldId {
/// #[field_id]
/// some_name: String,
/// }
/// ```
;
/// Verify that a `#[skip_schema]` field is excluded from the generated schema while its siblings
/// remain.
/// ```
/// # use buoyant_kernel as delta_kernel;
/// # use delta_kernel_derive::ToSchema;
/// # use delta_kernel::schema::ToSchema;
/// #[derive(ToSchema)]
/// pub struct WithSkippedField {
/// #[skip_schema]
/// skipped: String,
/// kept: i32,
/// }
/// let schema = WithSkippedField::to_schema();
/// assert!(schema.field("kept").is_some());
/// assert!(schema.field("skipped").is_none());
/// ```
;