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
//! Diesel MySQL Spatial is an extension to [Diesel] that provides support for
//! the MySQL flavour of OpenGIS spatial data types and the associated SQL functions.
//!
//! ## Declaring your schema
//! The types in [`diesel_mysql_spatial::sql_types`] may be used in Diesel `table!` macros.
//!
//! If you use the `diesel.toml` file for automatic schema generation, you need to add the
//! module to the `import_types` list:
//! ```toml
//! [print_schema]
//! ## Add types from `diesel_mysql_spatial` like `LineString`
//! import_types = ["diesel::sql_types::*", "diesel_mysql_spatial::sql_types::*"]
//! ```
//!
//! ## Constructing a query
//!
//! This crate provides Diesel DSL functions for most spatial SQL functions.
//! They live in [the `dsl` module](dsl).
//!
//! ```no_compile
//! use diesel_mysql_spatial::dsl::ST_IsValid;
//!
//! let valid_districts = districts.select(area).filter(ST_IsValid(area));
//! ```
//!
//! ## Serializing and Deserializing
//!
//! Diesel MySQL Spatial maps "Rust types" defined in [the `data_types` module] (e.g.
//! [`diesel_mysql_spatial::data_types::Point`]) to and from "SQL types" (e.g.
//! [`diesel_mysql_spatial::sql_types::Point`]). The latter types are only used to represent a
//! SQL type. You should only put the structs in `data_types` into your `Queryable` structs.
//!
//! [Diesel]: `diesel`
//! [`diesel_mysql_spatial::sql_types`]: `sql_types`
//! [`diesel_mysql_spatial::sql_types::Point`]: `sql_types::Point`
//! [`diesel_mysql_spatial::data_types::Point`]: `data_types::Point`
//! [the `data_types` module]: `data_types`

#[macro_use]
extern crate diesel;

use wkb::{WKBReadError, WKBWriteError};

/// The error type for (de-)serialization and conversion errors of spatial datatypes.
#[derive(thiserror::Error, Debug)]
pub enum GeometryError {
	/// Encountered WKB data in big endian byte order.
	///
	/// Should not occur as MySQL only uses little endian for the spatial datatypes.
	#[error("big endian WKB currently unsupported")]
	UnsupportedBigEndian,

	/// Unexpected data type encountered (e.g. a `Polygon` instead of a `Point`).
	#[error("Within in the format, there was an unexpected or wrong data type")]
	WrongType,

	/// A conversion could not be performed because a value precondition was not fulfilled
	///
	/// For example [`data_types::BoundingBox`] requires a `Polygon` in a specific shape.
	#[error("Invalid value for this conversion")]
	InvalidValue,

	/// Deserialization failed because of a format mismatch or an I/O error happened in a underlying layer.
	#[error("IO error: {0}")]
	IOError(#[from] std::io::Error),

	/// Encountered an unsupported geometry while serializing.
	#[error("Unsupported geometry")]
	UnsupportedGeoType,
}

impl From<WKBReadError> for GeometryError {
	fn from(e: WKBReadError) -> Self {
		match e {
			WKBReadError::UnsupportedBigEndian => GeometryError::UnsupportedBigEndian,
			WKBReadError::WrongType => GeometryError::WrongType,
			WKBReadError::IOError(e) => GeometryError::IOError(e),
		}
	}
}

impl From<WKBWriteError> for GeometryError {
	fn from(e: WKBWriteError) -> Self {
		match e {
			WKBWriteError::UnsupportedGeoTypeRect => GeometryError::UnsupportedGeoType,
			WKBWriteError::UnsupportedGeoTypeTriangle => GeometryError::UnsupportedGeoType,
			WKBWriteError::IOError(e) => GeometryError::IOError(e),
		}
	}
}

/// Spatial SQL types which may be used in table definitions
pub mod sql_types;

/// Structs that represent the Rust equivalent of spatial SQL types
pub mod data_types;

/// MySQL specific spatial functions for use in SQL expressions
///
/// All contained functions are also reexported in the `dsl` module.
pub mod functions;

/// Helper types that represent return types of spatial functions
///
/// See also: the [`functions`][`functions`] module.
///
/// All contained types are also reexported in the `dsl` module
pub mod helper_types;

/// Re-exports helper types and functions for SQL expressions
pub mod dsl;