laminar_connectors/postgres/cdc/
types.rs1use arrow_schema::DataType;
8
9pub const BOOL_OID: u32 = 16;
13pub const BYTEA_OID: u32 = 17;
15pub const CHAR_OID: u32 = 18;
17pub const INT8_OID: u32 = 20;
19pub const INT2_OID: u32 = 21;
21pub const INT4_OID: u32 = 23;
23pub const TEXT_OID: u32 = 25;
25pub const OID_OID: u32 = 26;
27pub const FLOAT4_OID: u32 = 700;
29pub const FLOAT8_OID: u32 = 701;
31pub const VARCHAR_OID: u32 = 1043;
33pub const DATE_OID: u32 = 1082;
35pub const TIME_OID: u32 = 1083;
37pub const TIMESTAMP_OID: u32 = 1114;
39pub const TIMESTAMPTZ_OID: u32 = 1184;
41pub const INTERVAL_OID: u32 = 1186;
43pub const NUMERIC_OID: u32 = 1700;
45pub const UUID_OID: u32 = 2950;
47pub const JSON_OID: u32 = 114;
49pub const JSONB_OID: u32 = 3802;
51pub const XML_OID: u32 = 142;
53pub const INET_OID: u32 = 869;
55pub const CIDR_OID: u32 = 650;
57pub const MACADDR_OID: u32 = 829;
59pub const BPCHAR_OID: u32 = 1042;
61pub const NAME_OID: u32 = 19;
63
64pub const BOOL_ARRAY_OID: u32 = 1000;
68pub const INT2_ARRAY_OID: u32 = 1005;
70pub const INT4_ARRAY_OID: u32 = 1007;
72pub const INT8_ARRAY_OID: u32 = 1016;
74pub const FLOAT4_ARRAY_OID: u32 = 1021;
76pub const FLOAT8_ARRAY_OID: u32 = 1022;
78pub const TEXT_ARRAY_OID: u32 = 1009;
80pub const VARCHAR_ARRAY_OID: u32 = 1015;
82
83#[derive(Debug, Clone, PartialEq, Eq)]
85pub struct PgColumn {
86 pub name: String,
88
89 pub type_oid: u32,
91
92 pub type_modifier: i32,
95
96 pub is_key: bool,
98}
99
100impl PgColumn {
101 #[must_use]
103 pub fn new(name: String, type_oid: u32, type_modifier: i32, is_key: bool) -> Self {
104 Self {
105 name,
106 type_oid,
107 type_modifier,
108 is_key,
109 }
110 }
111
112 #[must_use]
114 pub fn arrow_type(&self) -> DataType {
115 pg_type_to_arrow(self.type_oid)
116 }
117}
118
119#[must_use]
124pub fn pg_type_to_arrow(oid: u32) -> DataType {
125 match oid {
126 BOOL_OID => DataType::Boolean,
128
129 INT2_OID => DataType::Int16,
131 INT4_OID | OID_OID => DataType::Int32,
132 INT8_OID => DataType::Int64,
133
134 FLOAT4_OID => DataType::Float32,
136 FLOAT8_OID => DataType::Float64,
137
138 BYTEA_OID => DataType::Binary,
140
141 DATE_OID => DataType::Date32,
143 TIME_OID => DataType::Time64(arrow_schema::TimeUnit::Microsecond),
144 TIMESTAMP_OID => DataType::Timestamp(arrow_schema::TimeUnit::Microsecond, None),
145 TIMESTAMPTZ_OID => {
146 DataType::Timestamp(arrow_schema::TimeUnit::Microsecond, Some("UTC".into()))
147 }
148 _ => DataType::Utf8,
150 }
151}
152
153#[must_use]
155pub fn pg_type_name(oid: u32) -> &'static str {
156 match oid {
157 BOOL_OID => "bool",
158 BYTEA_OID => "bytea",
159 CHAR_OID => "char",
160 INT2_OID => "int2",
161 INT4_OID => "int4",
162 INT8_OID => "int8",
163 TEXT_OID => "text",
164 OID_OID => "oid",
165 FLOAT4_OID => "float4",
166 FLOAT8_OID => "float8",
167 VARCHAR_OID => "varchar",
168 BPCHAR_OID => "bpchar",
169 NAME_OID => "name",
170 DATE_OID => "date",
171 TIME_OID => "time",
172 TIMESTAMP_OID => "timestamp",
173 TIMESTAMPTZ_OID => "timestamptz",
174 INTERVAL_OID => "interval",
175 NUMERIC_OID => "numeric",
176 UUID_OID => "uuid",
177 JSON_OID => "json",
178 JSONB_OID => "jsonb",
179 XML_OID => "xml",
180 INET_OID => "inet",
181 CIDR_OID => "cidr",
182 MACADDR_OID => "macaddr",
183 _ => "unknown",
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190
191 #[test]
192 fn test_integer_type_mapping() {
193 assert_eq!(pg_type_to_arrow(INT2_OID), DataType::Int16);
194 assert_eq!(pg_type_to_arrow(INT4_OID), DataType::Int32);
195 assert_eq!(pg_type_to_arrow(INT8_OID), DataType::Int64);
196 }
197
198 #[test]
199 fn test_float_type_mapping() {
200 assert_eq!(pg_type_to_arrow(FLOAT4_OID), DataType::Float32);
201 assert_eq!(pg_type_to_arrow(FLOAT8_OID), DataType::Float64);
202 }
203
204 #[test]
205 fn test_text_type_mapping() {
206 assert_eq!(pg_type_to_arrow(TEXT_OID), DataType::Utf8);
207 assert_eq!(pg_type_to_arrow(VARCHAR_OID), DataType::Utf8);
208 assert_eq!(pg_type_to_arrow(BPCHAR_OID), DataType::Utf8);
209 assert_eq!(pg_type_to_arrow(NAME_OID), DataType::Utf8);
210 }
211
212 #[test]
213 fn test_bool_type_mapping() {
214 assert_eq!(pg_type_to_arrow(BOOL_OID), DataType::Boolean);
215 }
216
217 #[test]
218 fn test_timestamp_type_mapping() {
219 assert!(matches!(
220 pg_type_to_arrow(TIMESTAMP_OID),
221 DataType::Timestamp(arrow_schema::TimeUnit::Microsecond, None)
222 ));
223 assert!(matches!(
224 pg_type_to_arrow(TIMESTAMPTZ_OID),
225 DataType::Timestamp(arrow_schema::TimeUnit::Microsecond, Some(_))
226 ));
227 }
228
229 #[test]
230 fn test_date_time_mapping() {
231 assert_eq!(pg_type_to_arrow(DATE_OID), DataType::Date32);
232 assert!(matches!(
233 pg_type_to_arrow(TIME_OID),
234 DataType::Time64(arrow_schema::TimeUnit::Microsecond)
235 ));
236 }
237
238 #[test]
239 fn test_binary_type_mapping() {
240 assert_eq!(pg_type_to_arrow(BYTEA_OID), DataType::Binary);
241 }
242
243 #[test]
244 fn test_json_type_mapping() {
245 assert_eq!(pg_type_to_arrow(JSON_OID), DataType::Utf8);
246 assert_eq!(pg_type_to_arrow(JSONB_OID), DataType::Utf8);
247 }
248
249 #[test]
250 fn test_unknown_type_fallback() {
251 assert_eq!(pg_type_to_arrow(99999), DataType::Utf8);
252 }
253
254 #[test]
255 fn test_pg_column() {
256 let col = PgColumn::new("id".to_string(), INT8_OID, -1, true);
257 assert_eq!(col.name, "id");
258 assert_eq!(col.type_oid, INT8_OID);
259 assert!(col.is_key);
260 assert_eq!(col.arrow_type(), DataType::Int64);
261 }
262
263 #[test]
264 fn test_pg_type_name() {
265 assert_eq!(pg_type_name(INT4_OID), "int4");
266 assert_eq!(pg_type_name(TEXT_OID), "text");
267 assert_eq!(pg_type_name(BOOL_OID), "bool");
268 assert_eq!(pg_type_name(99999), "unknown");
269 }
270
271 #[test]
272 fn test_numeric_maps_to_utf8() {
273 assert_eq!(pg_type_to_arrow(NUMERIC_OID), DataType::Utf8);
275 }
276
277 #[test]
278 fn test_array_types_map_to_utf8() {
279 assert_eq!(pg_type_to_arrow(INT4_ARRAY_OID), DataType::Utf8);
280 assert_eq!(pg_type_to_arrow(TEXT_ARRAY_OID), DataType::Utf8);
281 }
282}