Skip to content

Commit

Permalink
feat: support Geography data type
Browse files Browse the repository at this point in the history
  • Loading branch information
b41sh committed Nov 6, 2024
1 parent d1a1d29 commit f0eaea5
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 18 deletions.
17 changes: 9 additions & 8 deletions bindings/nodejs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,15 @@ while (row) {

### Semi-Structured Data Types

| Databend | Node.js |
| ---------- | -------- |
| `ARRAY` | `Array` |
| `TUPLE` | `Array` |
| `MAP` | `Object` |
| `VARIANT` | `String` |
| `BITMAP` | `String` |
| `GEOMETRY` | `String` |
| Databend | Node.js |
| ----------- | -------- |
| `ARRAY` | `Array` |
| `TUPLE` | `Array` |
| `MAP` | `Object` |
| `VARIANT` | `String` |
| `BITMAP` | `String` |
| `GEOMETRY` | `String` |
| `GEOGRAPHY` | `String` |

Note: `VARIANT` is a json encoded string. Example:

Expand Down
1 change: 1 addition & 0 deletions bindings/nodejs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ impl ToNapiValue for Value {
databend_driver::Value::Bitmap(s) => String::to_napi_value(env, s),
databend_driver::Value::Variant(s) => String::to_napi_value(env, s),
databend_driver::Value::Geometry(s) => String::to_napi_value(env, s),
databend_driver::Value::Geography(s) => String::to_napi_value(env, s),
}
}
}
Expand Down
17 changes: 9 additions & 8 deletions bindings/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,15 @@ asyncio.run(main())

### Semi-Structured Data Types

| Databend | Python |
| ---------- | ------- |
| `ARRAY` | `list` |
| `TUPLE` | `tuple` |
| `MAP` | `dict` |
| `VARIANT` | `str` |
| `BITMAP` | `str` |
| `GEOMETRY` | `str` |
| Databend | Python |
| ----------- | ------- |
| `ARRAY` | `list` |
| `TUPLE` | `tuple` |
| `MAP` | `dict` |
| `VARIANT` | `str` |
| `BITMAP` | `str` |
| `GEOMETRY` | `str` |
| `GEOGRAPHY` | `str` |

Note: `VARIANT` is a json encoded string. Example:

Expand Down
1 change: 1 addition & 0 deletions bindings/python/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ impl IntoPy<PyObject> for Value {
databend_driver::Value::Bitmap(s) => s.into_py(py),
databend_driver::Value::Variant(s) => s.into_py(py),
databend_driver::Value::Geometry(s) => s.into_py(py),
databend_driver::Value::Geography(s) => s.into_py(py),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions driver/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ while let Some(row) = rows.next().await {
| `VARIANT` | `String` |
| `BITMAP` | `String` |
| `GEOMETRY` | `String` |
| `GEOGRAPHY` | `String` |

Note: `VARIANT` is a json encoded string. Example:

Expand Down
6 changes: 6 additions & 0 deletions sql/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub(crate) const ARROW_EXT_TYPE_VARIANT: &str = "Variant";
pub(crate) const ARROW_EXT_TYPE_BITMAP: &str = "Bitmap";
#[cfg(feature = "flight-sql")]
pub(crate) const ARROW_EXT_TYPE_GEOMETRY: &str = "Geometry";
#[cfg(feature = "flight-sql")]
pub(crate) const ARROW_EXT_TYPE_GEOGRAPHY: &str = "Geography";

use databend_client::response::SchemaField as APISchemaField;

Expand Down Expand Up @@ -89,6 +91,7 @@ pub enum DataType {
Variant,
Bitmap,
Geometry,
Geography,
// Generic(usize),
}

Expand Down Expand Up @@ -148,6 +151,7 @@ impl std::fmt::Display for DataType {
DataType::Variant => write!(f, "Variant"),
DataType::Bitmap => write!(f, "Bitmap"),
DataType::Geometry => write!(f, "Geometry"),
DataType::Geography => write!(f, "Geography"),
}
}
}
Expand Down Expand Up @@ -265,6 +269,7 @@ impl TryFrom<&TypeDesc<'_>> for DataType {
"Variant" => DataType::Variant,
"Bitmap" => DataType::Bitmap,
"Geometry" => DataType::Geometry,
"Geography" => DataType::Geography,
_ => return Err(Error::Parsing(format!("Unknown type: {:?}", desc))),
};
Ok(dt)
Expand Down Expand Up @@ -309,6 +314,7 @@ impl TryFrom<&Arc<ArrowField>> for Field {
ARROW_EXT_TYPE_VARIANT => DataType::Variant,
ARROW_EXT_TYPE_BITMAP => DataType::Bitmap,
ARROW_EXT_TYPE_GEOMETRY => DataType::Geometry,
ARROW_EXT_TYPE_GEOGRAPHY => DataType::Geography,
_ => {
return Err(Error::Parsing(format!(
"Unsupported extension datatype for arrow field: {:?}",
Expand Down
33 changes: 31 additions & 2 deletions sql/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const FALSE_VALUE: &str = "0";
use {
crate::schema::{
ARROW_EXT_TYPE_BITMAP, ARROW_EXT_TYPE_EMPTY_ARRAY, ARROW_EXT_TYPE_EMPTY_MAP,
ARROW_EXT_TYPE_GEOMETRY, ARROW_EXT_TYPE_VARIANT, EXTENSION_KEY,
ARROW_EXT_TYPE_GEOGRAPHY, ARROW_EXT_TYPE_GEOMETRY, ARROW_EXT_TYPE_VARIANT, EXTENSION_KEY,
},
arrow_array::{
Array as ArrowArray, BinaryArray, BooleanArray, Date32Array, Decimal128Array,
Expand Down Expand Up @@ -93,6 +93,7 @@ pub enum Value {
Bitmap(String),
Variant(String),
Geometry(String),
Geography(String),
}

impl Value {
Expand Down Expand Up @@ -143,6 +144,7 @@ impl Value {
Self::Bitmap(_) => DataType::Bitmap,
Self::Variant(_) => DataType::Variant,
Self::Geometry(_) => DataType::Geometry,
Self::Geography(_) => DataType::Geography,
}
}
}
Expand Down Expand Up @@ -224,6 +226,7 @@ impl TryFrom<(&DataType, &str)> for Value {
DataType::Bitmap => Ok(Self::Bitmap(v.to_string())),
DataType::Variant => Ok(Self::Variant(v.to_string())),
DataType::Geometry => Ok(Self::Geometry(v.to_string())),
DataType::Geography => Ok(Self::Geography(v.to_string())),

DataType::Array(_) | DataType::Map(_) | DataType::Tuple(_) => {
let mut reader = Cursor::new(v);
Expand Down Expand Up @@ -296,6 +299,18 @@ impl TryFrom<(&ArrowField, &Arc<dyn ArrowArray>, usize)> for Value {
None => Err(ConvertError::new("geometry", format!("{:?}", array)).into()),
};
}
ARROW_EXT_TYPE_GEOGRAPHY => {
if field.is_nullable() && array.is_null(seq) {
return Ok(Value::Null);
}
return match array.as_any().downcast_ref::<LargeBinaryArray>() {
Some(array) => {
let wkt = parse_geometry(array.value(seq))?;
Ok(Value::Geography(wkt))
}
None => Err(ConvertError::new("geography", format!("{:?}", array)).into()),
};
}
_ => {
return Err(ConvertError::new(
"extension",
Expand Down Expand Up @@ -499,6 +514,7 @@ impl TryFrom<Value> for String {
Value::Number(NumberValue::Decimal128(v, s)) => Ok(display_decimal_128(v, s.scale)),
Value::Number(NumberValue::Decimal256(v, s)) => Ok(display_decimal_256(v, s.scale)),
Value::Geometry(s) => Ok(s),
Value::Geography(s) => Ok(s),
Value::Variant(s) => Ok(s),
_ => Err(ConvertError::new("string", format!("{:?}", val)).into()),
}
Expand Down Expand Up @@ -788,7 +804,11 @@ fn encode_value(f: &mut std::fmt::Formatter<'_>, val: &Value, raw: bool) -> std:
}
Value::Number(n) => write!(f, "{}", n),
Value::Binary(s) => write!(f, "{}", hex::encode_upper(s)),
Value::String(s) | Value::Bitmap(s) | Value::Variant(s) | Value::Geometry(s) => {
Value::String(s)
| Value::Bitmap(s)
| Value::Variant(s)
| Value::Geometry(s)
| Value::Geography(s) => {
if raw {
write!(f, "{}", s)
} else {
Expand Down Expand Up @@ -1019,6 +1039,7 @@ impl ValueDecoder {
DataType::Bitmap => self.read_bitmap(reader),
DataType::Variant => self.read_variant(reader),
DataType::Geometry => self.read_geometry(reader),
DataType::Geography => self.read_geography(reader),
DataType::Array(inner_ty) => self.read_array(inner_ty.as_ref(), reader),
DataType::Map(inner_ty) => self.read_map(inner_ty.as_ref(), reader),
DataType::Tuple(inner_tys) => self.read_tuple(inner_tys.as_ref(), reader),
Expand Down Expand Up @@ -1171,6 +1192,14 @@ impl ValueDecoder {
Ok(Value::Geometry(unsafe { String::from_utf8_unchecked(buf) }))
}

fn read_geography<R: AsRef<[u8]>>(&self, reader: &mut Cursor<R>) -> Result<Value> {
let mut buf = Vec::new();
reader.read_quoted_text(&mut buf, b'\'')?;
Ok(Value::Geography(unsafe {
String::from_utf8_unchecked(buf)
}))
}

fn read_nullable<R: AsRef<[u8]>>(
&self,
ty: &DataType,
Expand Down

0 comments on commit f0eaea5

Please sign in to comment.