1use std::collections::HashMap;
16use std::sync::Arc;
17
18use arrow_array::ArrayRef;
19use arrow_schema::extension::{
20 EXTENSION_TYPE_METADATA_KEY, EXTENSION_TYPE_NAME_KEY, ExtensionType,
21};
22use arrow_schema::{ArrowError, DataType, Field, FieldRef, Schema, SchemaRef};
23use parquet_variant_compute::VariantType;
24use serde::{Deserialize, Serialize};
25use snafu::{ResultExt, ensure};
26
27use crate::error::{InvalidJson2LayoutSnafu, SerializeSnafu};
28pub use crate::json::JSON2_REMAINDER_FIELD_NAME;
29use crate::json::JsonSettings;
30use crate::schema::Metadata;
31
32pub fn align_schema_with_json_array(schema: SchemaRef, columns: &[ArrayRef]) -> SchemaRef {
34 if schema.fields().iter().all(|f| !is_json2_extension_type(f)) {
35 return schema;
36 }
37
38 let mut fields = Vec::with_capacity(schema.fields().len());
39 for (field, array) in schema.fields().iter().zip(columns) {
40 if !is_json2_extension_type(field) {
41 fields.push(field.clone());
42 continue;
43 }
44
45 let mut field = field.as_ref().clone();
46 field.set_data_type(array.data_type().clone());
47 fields.push(Arc::new(field));
48 }
49
50 Arc::new(Schema::new_with_metadata(fields, schema.metadata().clone()))
51}
52
53const LEGACY_JSON_STRUCTURE_SETTINGS_KEY: &str = "json_structure_settings";
54const JSON2_LAYOUT_V1: u8 = 1;
55const JSON2_LAYOUT_V2: u8 = 2;
56
57#[derive(Debug, Clone, PartialEq, Eq)]
59pub struct Json2PhysicalLayout {
60 version: u8,
61}
62
63impl Json2PhysicalLayout {
64 pub fn try_from_root(field: &Field) -> crate::error::Result<Self> {
76 ensure!(
77 is_json2_extension_type(field),
78 InvalidJson2LayoutSnafu {
79 reason: format!("field '{}' is not a JSON2 extension", field.name()),
80 }
81 );
82
83 let version = match field.extension_type_name() {
84 Some(Json2ExtensionType::NAME) => field
85 .metadata()
86 .get(EXTENSION_TYPE_METADATA_KEY)
87 .map(|x| parse_version(x))
88 .transpose()?
89 .flatten()
90 .unwrap_or(JSON2_LAYOUT_V1),
91 _ => JSON2_LAYOUT_V1,
92 };
93 ensure!(
94 matches!(version, JSON2_LAYOUT_V1 | JSON2_LAYOUT_V2),
95 InvalidJson2LayoutSnafu {
96 reason: format!("unsupported JSON2 layout version: {version}"),
97 }
98 );
99 Ok(Self { version })
100 }
101
102 pub fn is_version_2(&self) -> bool {
104 self.version == JSON2_LAYOUT_V2
105 }
106}
107
108fn parse_version(metadata: &str) -> crate::error::Result<Option<u8>> {
109 serde_json::from_str::<JsonMetadata>(metadata)
110 .map(|x| x.layout_version)
111 .map_err(|e| {
112 InvalidJson2LayoutSnafu {
113 reason: format!(r#"invalid extension metadata: "{metadata}", error: {e}"#),
114 }
115 .build()
116 })
117}
118
119pub(crate) fn json2_remainder_field(field: &Field) -> crate::error::Result<Option<&FieldRef>> {
121 let layout = Json2PhysicalLayout::try_from_root(field)?;
122 if !layout.is_version_2() {
123 return Ok(None);
124 }
125
126 let remainder = if let DataType::Struct(fields) = field.data_type() {
127 fields
128 .iter()
129 .find(|x| x.name() == JSON2_REMAINDER_FIELD_NAME)
130 } else {
131 None
132 };
133
134 if let Some(remainder) = remainder {
135 let _ = remainder.try_extension_type::<VariantType>().map_err(|e| {
136 InvalidJson2LayoutSnafu {
137 reason: e.to_string(),
138 }
139 .build()
140 })?;
141 }
142 Ok(remainder)
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
146pub struct JsonMetadata {
147 json_settings: JsonSettings,
149 #[serde(default, skip_serializing_if = "Option::is_none")]
151 layout_version: Option<u8>,
152}
153
154impl JsonMetadata {
155 pub fn new(json_settings: JsonSettings) -> Self {
157 Self {
158 json_settings,
159 layout_version: Some(JSON2_LAYOUT_V2),
160 }
161 }
162
163 pub fn new_v1(json_settings: JsonSettings) -> Self {
165 Self {
166 json_settings,
167 layout_version: None,
168 }
169 }
170
171 pub fn json_settings(&self) -> &JsonSettings {
173 &self.json_settings
174 }
175
176 pub fn into_json_settings(self) -> JsonSettings {
178 self.json_settings
179 }
180
181 pub fn is_version_2(&self) -> bool {
183 self.layout_version == Some(JSON2_LAYOUT_V2)
184 }
185}
186
187impl Default for JsonMetadata {
188 fn default() -> Self {
189 Self::new(JsonSettings::default())
190 }
191}
192
193#[derive(Debug, Clone, Default)]
195pub struct JsonExtensionType;
196
197impl ExtensionType for JsonExtensionType {
198 const NAME: &'static str = "greptime.json";
199 type Metadata = ();
200
201 fn metadata(&self) -> &Self::Metadata {
202 &()
203 }
204
205 fn serialize_metadata(&self) -> Option<String> {
206 None
207 }
208
209 fn deserialize_metadata(_metadata: Option<&str>) -> Result<Self::Metadata, ArrowError> {
210 Ok(())
211 }
212
213 fn supports_data_type(&self, data_type: &DataType) -> Result<(), ArrowError> {
214 match data_type {
215 DataType::Binary | DataType::Null => Ok(()),
216 t => Err(ArrowError::InvalidArgumentError(format!(
217 "Unexpected data type {t} for JsonExtensionType"
218 ))),
219 }
220 }
221
222 fn try_new(data_type: &DataType, _metadata: Self::Metadata) -> Result<Self, ArrowError> {
223 Self.supports_data_type(data_type).map(|_| Self)
224 }
225}
226
227#[derive(Debug, Clone, Default)]
229pub struct Json2ExtensionType(Arc<JsonMetadata>);
230
231impl Json2ExtensionType {
232 pub fn new(metadata: Arc<JsonMetadata>) -> Self {
234 Self(metadata)
235 }
236}
237
238impl ExtensionType for Json2ExtensionType {
239 const NAME: &'static str = "greptime.json2";
240 type Metadata = Arc<JsonMetadata>;
241
242 fn metadata(&self) -> &Self::Metadata {
243 &self.0
244 }
245
246 fn serialize_metadata(&self) -> Option<String> {
247 serde_json::to_string(self.metadata()).ok()
248 }
249
250 fn deserialize_metadata(metadata: Option<&str>) -> Result<Self::Metadata, ArrowError> {
251 if let Some(metadata) = metadata {
252 let metadata = serde_json::from_str(metadata).map_err(|e| {
253 ArrowError::ParseError(format!("Failed to deserialize JSON metadata: {}", e))
254 })?;
255 Ok(Arc::new(metadata))
256 } else {
257 Ok(Arc::new(JsonMetadata::new_v1(JsonSettings::default())))
258 }
259 }
260
261 fn supports_data_type(&self, data_type: &DataType) -> Result<(), ArrowError> {
262 match data_type {
263 DataType::Struct(_)
265 | DataType::List(_)
267 | DataType::ListView(_)
268 | DataType::LargeList(_)
269 | DataType::LargeListView(_)
270 | DataType::Utf8
272 | DataType::Utf8View
273 | DataType::LargeUtf8
274 | DataType::Int8
276 | DataType::Int16
277 | DataType::Int32
278 | DataType::Int64
279 | DataType::UInt8
280 | DataType::UInt16
281 | DataType::UInt32
282 | DataType::UInt64
283 | DataType::Float32
284 | DataType::Float64
285 | DataType::Boolean
287 | DataType::Null
289 | DataType::Binary => Ok(()),
291 dt => Err(ArrowError::SchemaError(format!(
292 "Unexpected data type {dt}"
293 ))),
294 }
295 }
296
297 fn try_new(data_type: &DataType, metadata: Self::Metadata) -> Result<Self, ArrowError> {
298 let json = Self(metadata);
299 json.supports_data_type(data_type)?;
300 Ok(json)
301 }
302}
303
304pub fn json2_metadata_with_updated_settings(
308 current_metadata: &Metadata,
309 settings: JsonSettings,
310) -> crate::error::Result<Metadata> {
311 let json_metadata = JsonMetadata::new(settings);
312
313 let mut metadata = current_metadata.clone();
314 metadata.insert(
315 EXTENSION_TYPE_NAME_KEY.to_string(),
316 Json2ExtensionType::NAME.to_string(),
317 );
318 metadata.insert(
319 EXTENSION_TYPE_METADATA_KEY.to_string(),
320 serde_json::to_string(&json_metadata).context(SerializeSnafu)?,
321 );
322 Ok(metadata)
323}
324
325pub fn is_any_json_extension_type<T: AsRef<Field>>(field: T) -> bool {
327 let name = field.as_ref().extension_type_name();
328 name == Some(JsonExtensionType::NAME) || name == Some(Json2ExtensionType::NAME)
329}
330
331pub fn parse_legacy_json2_settings(
333 metadata: &HashMap<String, String>,
334) -> crate::error::Result<Option<JsonSettings>> {
335 #[derive(Deserialize)]
336 struct LegacyJsonMetadata {
337 #[serde(default)]
338 json_settings: Option<JsonSettings>,
339 }
340
341 if metadata.get(EXTENSION_TYPE_NAME_KEY).map(String::as_str) != Some(JsonExtensionType::NAME) {
342 return Ok(None);
343 }
344
345 metadata
346 .get(EXTENSION_TYPE_METADATA_KEY)
347 .map(|json| {
348 serde_json::from_str::<LegacyJsonMetadata>(json)
349 .map(|x| x.json_settings)
350 .context(crate::error::DeserializeSnafu { json })
351 })
352 .transpose()
353 .map(Option::flatten)
354}
355
356pub fn is_legacy_json2_extension_type<T: AsRef<Field>>(field: T) -> bool {
362 let field = field.as_ref();
363 if field.extension_type_name() != Some(JsonExtensionType::NAME)
364 || !matches!(field.data_type(), DataType::Struct(_))
365 {
366 return false;
367 }
368
369 field
370 .metadata()
371 .get(EXTENSION_TYPE_METADATA_KEY)
372 .and_then(|json| serde_json::from_str::<serde_json::Value>(json).ok())
373 .is_some_and(|metadata| metadata.get(LEGACY_JSON_STRUCTURE_SETTINGS_KEY).is_some())
374}
375
376pub fn is_json2_extension_type<T: AsRef<Field>>(field: T) -> bool {
382 let field = field.as_ref();
383 field.extension_type_name() == Some(Json2ExtensionType::NAME)
384 || parse_legacy_json2_settings(field.metadata()).is_ok_and(|x| x.is_some())
385 || is_legacy_json2_extension_type(field)
386}
387
388#[cfg(test)]
389mod tests {
390 use std::collections::HashMap;
391
392 use arrow_schema::extension::{EXTENSION_TYPE_METADATA_KEY, EXTENSION_TYPE_NAME_KEY};
393 use arrow_schema::{Field, Fields};
394
395 use super::*;
396 use crate::vectors::json::variant::variant_field;
397
398 #[test]
399 fn test_json2_extension_type_detection() {
400 let extension = Json2ExtensionType::new(Arc::new(JsonMetadata::default()));
401 let json2 = Field::new("j", DataType::Struct(Fields::empty()), true)
402 .with_extension_type(extension.clone());
403 let projection = Field::new("j", DataType::Binary, true).with_extension_type(extension);
405 let legacy_json2 = Field::new("j", DataType::Struct(Fields::empty()), true).with_metadata(
406 HashMap::from([
407 (
408 EXTENSION_TYPE_NAME_KEY.to_string(),
409 JsonExtensionType::NAME.to_string(),
410 ),
411 (
412 EXTENSION_TYPE_METADATA_KEY.to_string(),
413 serde_json::json!({ "json_settings": JsonSettings::default() }).to_string(),
414 ),
415 ]),
416 );
417 let legacy_structure_metadata = HashMap::from([
420 (
421 EXTENSION_TYPE_NAME_KEY.to_string(),
422 JsonExtensionType::NAME.to_string(),
423 ),
424 (
425 EXTENSION_TYPE_METADATA_KEY.to_string(),
426 serde_json::json!({
427 (LEGACY_JSON_STRUCTURE_SETTINGS_KEY): { "Structured": null }
428 })
429 .to_string(),
430 ),
431 ]);
432 let pre_type_hint_json2 = Field::new("j", DataType::Struct(Fields::empty()), true)
433 .with_metadata(legacy_structure_metadata.clone());
434 let legacy_jsonb =
435 Field::new("j", DataType::Binary, true).with_metadata(legacy_structure_metadata);
436
437 assert!(is_json2_extension_type(&json2));
438 assert!(is_json2_extension_type(&projection));
439 assert!(is_json2_extension_type(&legacy_json2));
440 assert!(is_legacy_json2_extension_type(&pre_type_hint_json2));
441 assert!(is_json2_extension_type(&pre_type_hint_json2));
442 assert_eq!(
443 Some(JsonSettings::default()),
444 parse_legacy_json2_settings(legacy_json2.metadata()).unwrap()
445 );
446 assert!(!is_legacy_json2_extension_type(&legacy_jsonb));
447 assert!(!is_json2_extension_type(&legacy_jsonb));
448 assert!(JsonExtensionType::try_new(&DataType::Binary, ()).is_ok());
449 assert!(JsonExtensionType::try_new(&DataType::Null, ()).is_ok());
450 assert!(JsonExtensionType::try_new(&DataType::Struct(Fields::empty()), ()).is_err());
451 }
452
453 #[test]
454 fn test_json_metadata_layout_version_compatibility() -> serde_json::Result<()> {
455 let legacy: JsonMetadata = serde_json::from_str(r#"{"json_settings":{}}"#)?;
456 assert!(!legacy.is_version_2());
457
458 let metadata = JsonMetadata::new(JsonSettings::default());
459 assert!(metadata.is_version_2());
460 let serialized = serde_json::to_string(&metadata)?;
461 let deserialized: JsonMetadata = serde_json::from_str(&serialized)?;
462 assert!(deserialized.is_version_2());
463 assert_eq!(deserialized, metadata);
464 Ok(())
465 }
466
467 #[test]
468 fn test_json2_metadata_with_updated_settings_upgrades_layout() -> crate::error::Result<()> {
469 for (name, json) in [
470 (JsonExtensionType::NAME, r#"{"json_settings":{}}"#),
471 (Json2ExtensionType::NAME, r#"{"json_settings":{}}"#),
472 (
473 Json2ExtensionType::NAME,
474 r#"{"json_settings":{},"layout_version":2}"#,
475 ),
476 ] {
477 let metadata = HashMap::from([
478 (EXTENSION_TYPE_NAME_KEY.to_string(), name.to_string()),
479 (EXTENSION_TYPE_METADATA_KEY.to_string(), json.to_string()),
480 ("other".to_string(), "kept".to_string()),
481 ]);
482 let settings = JsonSettings::try_new(vec![], Some(10))?;
483 let updated = json2_metadata_with_updated_settings(&metadata, settings.clone())?;
484 assert_eq!(Some("kept"), updated.get("other").map(String::as_str));
485 assert_eq!(
486 Some(Json2ExtensionType::NAME),
487 updated.get(EXTENSION_TYPE_NAME_KEY).map(String::as_str)
488 );
489 let json_metadata: JsonMetadata =
490 serde_json::from_str(updated.get(EXTENSION_TYPE_METADATA_KEY).unwrap()).unwrap();
491 assert_eq!(JsonMetadata::new(settings), json_metadata);
492 }
493 Ok(())
494 }
495
496 #[test]
497 fn test_parse_json2_physical_layout() -> crate::error::Result<()> {
498 let legacy = Field::new("data", DataType::Struct(Fields::empty()), true)
499 .with_extension_type(Json2ExtensionType::new(Arc::new(JsonMetadata::new_v1(
500 JsonSettings::default(),
501 ))));
502 assert!(!Json2PhysicalLayout::try_from_root(&legacy)?.is_version_2());
503
504 let v2 = Field::new(
505 "data",
506 DataType::Struct(
507 vec![
508 Arc::new(variant_field(JSON2_REMAINDER_FIELD_NAME, true)),
509 Arc::new(Field::new("count", DataType::Int64, true)),
510 ]
511 .into(),
512 ),
513 true,
514 )
515 .with_extension_type(Json2ExtensionType::new(Arc::new(JsonMetadata::new(
516 JsonSettings::default(),
517 ))));
518 assert!(Json2PhysicalLayout::try_from_root(&v2)?.is_version_2());
519 let remainder = json2_remainder_field(&v2)?.unwrap();
520 assert_eq!(JSON2_REMAINDER_FIELD_NAME, remainder.name());
521 Ok(())
522 }
523
524 #[test]
525 fn test_reject_invalid_json2_physical_layout() {
526 let field = Field::new("data", DataType::Struct(Fields::empty()), true);
527 assert!(Json2PhysicalLayout::try_from_root(&field).is_err());
528
529 let metadata =
530 Json2ExtensionType::new(Arc::new(JsonMetadata::new(JsonSettings::default())));
531 let missing = Field::new("data", DataType::Struct(Fields::empty()), true)
532 .with_extension_type(metadata.clone());
533 assert!(json2_remainder_field(&missing).is_ok_and(|x| x.is_none()));
534
535 let invalid = Field::new(
536 "data",
537 DataType::Struct(
538 vec![Arc::new(Field::new(
539 JSON2_REMAINDER_FIELD_NAME,
540 DataType::Binary,
541 true,
542 ))]
543 .into(),
544 ),
545 true,
546 )
547 .with_extension_type(metadata);
548 assert!(json2_remainder_field(&invalid).is_err());
549
550 let future = Field::new("data", DataType::Struct(Fields::empty()), true)
551 .with_extension_type(Json2ExtensionType::new(Arc::new(JsonMetadata {
552 json_settings: JsonSettings::default(),
553 layout_version: Some(JSON2_LAYOUT_V2 + 1),
554 })));
555 assert!(Json2PhysicalLayout::try_from_root(&future).is_err());
556 }
557}