rdf_fusion_encoding/plain_term/
row_builder.rs

1use crate::plain_term::encoding::{PlainTermEncodingField, PlainTermType};
2use crate::plain_term::{PlainTermArray, PlainTermEncoding};
3use datafusion::arrow::array::{StringBuilder, StructBuilder, UInt8Builder};
4use rdf_fusion_model::{BlankNodeRef, LiteralRef, NamedNodeRef, TermRef};
5use std::sync::Arc;
6
7/// Provides a convenient API for building arrays (element-by-element) of RDF terms with the
8/// [PlainTermEncoding]. The documentation of the encoding provides additional information.
9pub struct PlainTermArrayElementBuilder {
10    /// The underlying [StructBuilder].
11    builder: StructBuilder,
12}
13
14impl Default for PlainTermArrayElementBuilder {
15    fn default() -> Self {
16        Self::new(0)
17    }
18}
19
20impl PlainTermArrayElementBuilder {
21    /// Create a [PlainTermArrayElementBuilder] with the given `capacity`.
22    pub fn new(capacity: usize) -> Self {
23        Self {
24            builder: StructBuilder::from_fields(PlainTermEncoding::fields(), capacity),
25        }
26    }
27
28    /// Appends a null value to the array.
29    pub fn append_null(&mut self) {
30        self.builder
31            .field_builder::<UInt8Builder>(PlainTermEncodingField::TermType.index())
32            .unwrap()
33            .append_null();
34        self.builder
35            .field_builder::<StringBuilder>(PlainTermEncodingField::Value.index())
36            .unwrap()
37            .append_null();
38        self.builder
39            .field_builder::<StringBuilder>(PlainTermEncodingField::DataType.index())
40            .unwrap()
41            .append_null();
42        self.builder
43            .field_builder::<StringBuilder>(PlainTermEncodingField::LanguageTag.index())
44            .unwrap()
45            .append_null();
46        self.builder.append(false)
47    }
48
49    /// Appends a name node to the array.
50    pub fn append_named_node(&mut self, named_node: NamedNodeRef<'_>) {
51        self.append(PlainTermType::NamedNode, named_node.as_str(), None, None);
52    }
53
54    /// Appends a blank node to the array.
55    pub fn append_blank_node(&mut self, blank_node: BlankNodeRef<'_>) {
56        self.append(PlainTermType::BlankNode, blank_node.as_str(), None, None);
57    }
58
59    /// Appends a literal to the array.
60    ///
61    /// This encoding retains invalid lexical values for typed RDF literals.
62    pub fn append_literal(&mut self, literal: LiteralRef<'_>) {
63        self.append(
64            PlainTermType::Literal,
65            literal.value(),
66            Some(literal.datatype().as_str()),
67            literal.language(),
68        );
69    }
70
71    /// Appends an arbitrary RDF term to the array.
72    ///
73    /// This encoding retains invalid lexical values for typed RDF literals.
74    pub fn append_term(&mut self, literal: TermRef<'_>) {
75        match literal {
76            TermRef::NamedNode(nn) => self.append_named_node(nn),
77            TermRef::BlankNode(bnode) => self.append_blank_node(bnode),
78            TermRef::Literal(lit) => self.append_literal(lit),
79        }
80    }
81
82    /// Appends the given RDF term to the array.
83    ///
84    /// All literals must pass a `data_type`.
85    fn append(
86        &mut self,
87        term_type: PlainTermType,
88        value: &str,
89        data_type: Option<&str>,
90        language_tag: Option<&str>,
91    ) {
92        assert!(
93            !(term_type == PlainTermType::Literal && data_type.is_none()),
94            "Literal term must have a data type"
95        );
96
97        self.builder
98            .field_builder::<UInt8Builder>(PlainTermEncodingField::TermType.index())
99            .unwrap()
100            .append_value(term_type.into());
101
102        self.builder
103            .field_builder::<StringBuilder>(PlainTermEncodingField::Value.index())
104            .unwrap()
105            .append_value(value);
106
107        let data_type_builder = self
108            .builder
109            .field_builder::<StringBuilder>(PlainTermEncodingField::DataType.index())
110            .unwrap();
111        match data_type {
112            None => data_type_builder.append_null(),
113            Some(data_type) => data_type_builder.append_value(data_type),
114        }
115
116        let language_tag_builder = self
117            .builder
118            .field_builder::<StringBuilder>(PlainTermEncodingField::LanguageTag.index())
119            .unwrap();
120        match language_tag {
121            None => language_tag_builder.append_null(),
122            Some(language_tag) => language_tag_builder.append_value(language_tag),
123        }
124
125        self.builder.append(true)
126    }
127
128    pub fn finish(mut self) -> PlainTermArray {
129        PlainTermArray::new_unchecked(Arc::new(self.builder.finish()))
130    }
131}