1use crate::{
7 ewkb::{
8 self, AsEwkbGeometry, AsEwkbGeometryCollection, AsEwkbLineString, AsEwkbMultiLineString,
9 AsEwkbMultiPoint, AsEwkbMultiPolygon, AsEwkbPoint, AsEwkbPolygon, EwkbRead, EwkbWrite,
10 },
11 twkb::{self, TwkbGeom},
12 types::{LineString, Point, Polygon},
13};
14use bytes::{BufMut, BytesMut};
15use postgres_types::{FromSql, IsNull, ToSql, Type, accepts, to_sql_checked};
16use std::{error::Error, io::Cursor};
17
18macro_rules! accepts_geography {
19 () => {
20 fn accepts(ty: &Type) -> bool {
21 match ty.name() {
22 "geography" | "geometry" => true,
23 _ => false,
24 }
25 }
26 };
27}
28
29impl ToSql for ewkb::EwkbPoint<'_> {
30 accepts_geography!();
31
32 to_sql_checked!();
33
34 fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
35 self.write_ewkb(&mut out.writer())?;
36 Ok(IsNull::No)
37 }
38}
39
40macro_rules! impl_sql_for_point_type {
41 ($ptype:ident) => {
42 impl<'a> FromSql<'a> for ewkb::$ptype {
43 accepts_geography!();
44
45 fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
46 let mut rdr = Cursor::new(raw);
47 ewkb::$ptype::read_ewkb(&mut rdr)
48 .map_err(|_| format!("cannot convert {} to {}", ty, stringify!($ptype)).into())
49 }
50 }
51
52 impl ToSql for ewkb::$ptype {
53 to_sql_checked!();
54
55 accepts_geography!();
56
57 fn to_sql(
58 &self,
59 _: &Type,
60 out: &mut BytesMut,
61 ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
62 self.as_ewkb().write_ewkb(&mut out.writer())?;
63 Ok(IsNull::No)
64 }
65 }
66 };
67}
68
69impl_sql_for_point_type!(Point);
70impl_sql_for_point_type!(PointZ);
71impl_sql_for_point_type!(PointM);
72impl_sql_for_point_type!(PointZM);
73
74macro_rules! impl_sql_for_geom_type {
75 ($geotype:ident) => {
76 impl<'a, T> FromSql<'a> for ewkb::$geotype<T>
77 where
78 T: 'a + Point + EwkbRead,
79 {
80 accepts_geography!();
81
82 fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
83 let mut rdr = Cursor::new(raw);
84 ewkb::$geotype::<T>::read_ewkb(&mut rdr).map_err(|_| {
85 format!("cannot convert {} to {}", ty, stringify!($geotype)).into()
86 })
87 }
88 }
89
90 impl<'a, T> ToSql for ewkb::$geotype<T>
91 where
92 T: 'a + Point + EwkbRead,
93 {
94 to_sql_checked!();
95
96 accepts_geography!();
97
98 fn to_sql(
99 &self,
100 _: &Type,
101 out: &mut BytesMut,
102 ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
103 self.as_ewkb().write_ewkb(&mut out.writer())?;
104 Ok(IsNull::No)
105 }
106 }
107 };
108}
109
110impl_sql_for_geom_type!(LineStringT);
111impl_sql_for_geom_type!(PolygonT);
112impl_sql_for_geom_type!(MultiPointT);
113impl_sql_for_geom_type!(MultiLineStringT);
114impl_sql_for_geom_type!(MultiPolygonT);
115
116macro_rules! impl_sql_for_ewkb_type {
117 ($ewkbtype:ident contains points) => {
118 impl<'a, T, I> ToSql for ewkb::$ewkbtype<'a, T, I>
119 where
120 T: 'a + Point,
121 I: 'a + Iterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>,
122 {
123 to_sql_checked!();
124
125 accepts_geography!();
126
127 fn to_sql(
128 &self,
129 _: &Type,
130 out: &mut BytesMut,
131 ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
132 self.write_ewkb(&mut out.writer())?;
133 Ok(IsNull::No)
134 }
135 }
136 };
137 ($ewkbtype:ident contains $itemtypetrait:ident) => {
138 impl<'a, P, I, T, J> ToSql for ewkb::$ewkbtype<'a, P, I, T, J>
139 where
140 P: 'a + Point,
141 I: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
142 T: 'a + $itemtypetrait<'a, ItemType = P, Iter = I>,
143 J: 'a + Iterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>,
144 {
145 to_sql_checked!();
146
147 accepts_geography!();
148
149 fn to_sql(
150 &self,
151 _: &Type,
152 out: &mut BytesMut,
153 ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
154 self.write_ewkb(&mut out.writer())?;
155 Ok(IsNull::No)
156 }
157 }
158 };
159 (multipoly $ewkbtype:ident contains $itemtypetrait:ident) => {
160 impl<'a, P, I, L, K, T, J> ToSql for ewkb::$ewkbtype<'a, P, I, L, K, T, J>
161 where
162 P: 'a + Point,
163 I: 'a + Iterator<Item = &'a P> + ExactSizeIterator<Item = &'a P>,
164 L: 'a + LineString<'a, ItemType = P, Iter = I>,
165 K: 'a + Iterator<Item = &'a L> + ExactSizeIterator<Item = &'a L>,
166 T: 'a + $itemtypetrait<'a, ItemType = L, Iter = K>,
167 J: 'a + Iterator<Item = &'a T> + ExactSizeIterator<Item = &'a T>,
168 {
169 to_sql_checked!();
170
171 accepts_geography!();
172
173 fn to_sql(
174 &self,
175 _: &Type,
176 out: &mut BytesMut,
177 ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
178 self.write_ewkb(&mut out.writer())?;
179 Ok(IsNull::No)
180 }
181 }
182 };
183}
184
185impl_sql_for_ewkb_type!(EwkbLineString contains points);
186impl_sql_for_ewkb_type!(EwkbPolygon contains LineString);
187impl_sql_for_ewkb_type!(EwkbMultiPoint contains points);
188impl_sql_for_ewkb_type!(EwkbMultiLineString contains LineString);
189impl_sql_for_ewkb_type!(multipoly EwkbMultiPolygon contains Polygon);
190
191impl<P> FromSql<'_> for ewkb::GeometryT<P>
192where
193 P: Point + EwkbRead,
194{
195 accepts_geography!();
196
197 fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
198 let mut rdr = Cursor::new(raw);
199 ewkb::GeometryT::<P>::read_ewkb(&mut rdr)
200 .map_err(|_| format!("cannot convert {} to {}", ty, stringify!(P)).into())
201 }
202}
203
204macro_rules! impl_geometry_to_sql {
207 ($ptype:path) => {
208 impl ToSql for ewkb::GeometryT<$ptype> {
209 to_sql_checked!();
210
211 accepts_geography!();
212
213 fn to_sql(
214 &self,
215 _: &Type,
216 out: &mut BytesMut,
217 ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
218 self.as_ewkb().write_ewkb(&mut out.writer())?;
219 Ok(IsNull::No)
220 }
221 }
222 };
223}
224
225impl_geometry_to_sql!(ewkb::Point);
226impl_geometry_to_sql!(ewkb::PointZ);
227impl_geometry_to_sql!(ewkb::PointM);
228impl_geometry_to_sql!(ewkb::PointZM);
229
230impl<P> FromSql<'_> for ewkb::GeometryCollectionT<P>
231where
232 P: Point + EwkbRead,
233{
234 accepts_geography!();
235
236 fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
237 let mut rdr = Cursor::new(raw);
238 ewkb::GeometryCollectionT::<P>::read_ewkb(&mut rdr)
239 .map_err(|_| format!("cannot convert {} to {}", ty, stringify!(P)).into())
240 }
241}
242
243impl<P> ToSql for ewkb::GeometryCollectionT<P>
244where
245 P: Point + EwkbRead,
246{
247 to_sql_checked!();
248
249 accepts_geography!();
250
251 fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
252 self.as_ewkb().write_ewkb(&mut out.writer())?;
253 Ok(IsNull::No)
254 }
255}
256
257impl FromSql<'_> for twkb::Point {
260 accepts!(BYTEA);
261
262 fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
263 let mut rdr = Cursor::new(raw);
264 twkb::Point::read_twkb(&mut rdr)
265 .map_err(|_| format!("cannot convert {} to Point", ty).into())
266 }
267}
268
269impl FromSql<'_> for twkb::LineString {
270 accepts!(BYTEA);
271
272 fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
273 let mut rdr = Cursor::new(raw);
274 twkb::LineString::read_twkb(&mut rdr)
275 .map_err(|_| format!("cannot convert {} to LineString", ty).into())
276 }
277}
278
279impl FromSql<'_> for twkb::Polygon {
280 accepts!(BYTEA);
281
282 fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
283 let mut rdr = Cursor::new(raw);
284 twkb::Polygon::read_twkb(&mut rdr)
285 .map_err(|_| format!("cannot convert {} to Polygon", ty).into())
286 }
287}
288
289impl FromSql<'_> for twkb::MultiPoint {
290 accepts!(BYTEA);
291
292 fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
293 let mut rdr = Cursor::new(raw);
294 twkb::MultiPoint::read_twkb(&mut rdr)
295 .map_err(|_| format!("cannot convert {} to MultiPoint", ty).into())
296 }
297}
298
299impl FromSql<'_> for twkb::MultiLineString {
300 accepts!(BYTEA);
301
302 fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
303 let mut rdr = Cursor::new(raw);
304 twkb::MultiLineString::read_twkb(&mut rdr)
305 .map_err(|_| format!("cannot convert {} to MultiLineString", ty).into())
306 }
307}
308
309impl FromSql<'_> for twkb::MultiPolygon {
310 accepts!(BYTEA);
311
312 fn from_sql(ty: &Type, raw: &[u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
313 let mut rdr = Cursor::new(raw);
314 twkb::MultiPolygon::read_twkb(&mut rdr)
315 .map_err(|_| format!("cannot convert {} to MultiPolygon", ty).into())
316 }
317}
318
319#[cfg(test)]
320mod tests {
321 use crate::{
322 ewkb::{self, AsEwkbLineString, AsEwkbPoint},
323 twkb, types as postgis,
324 };
325 use postgres::{Client, NoTls};
326 use std::env;
327
328 macro_rules! or_panic {
329 ($e:expr) => {
330 match $e {
331 Ok(ok) => ok,
332 Err(err) => panic!("{:#?}", err),
333 }
334 };
335 }
336
337 fn connect() -> Client {
338 match env::var("DBCONN") {
339 Result::Ok(val) => Client::connect(&val as &str, NoTls),
340 Result::Err(err) => panic!("{:#?}", err),
341 }
342 .unwrap()
343 }
344
345 #[test]
346 #[ignore]
347 #[rustfmt::skip]
348 fn test_insert_point() {
349 let mut client = connect();
350 or_panic!(client.execute("CREATE TEMPORARY TABLE geomtests (geom geometry(Point))", &[]));
351
352 let point = ewkb::Point::new(10.0, -20.0, None);
354 or_panic!(client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&point]));
355 let result = or_panic!(client.query("SELECT geom=ST_GeomFromEWKT('POINT(10 -20)') FROM geomtests", &[]));
356 assert!(result.iter().map(|r| r.get::<_, bool>(0)).last().unwrap());
357 or_panic!(client.execute("TRUNCATE geomtests", &[]));
358
359 let point = ewkb::Point::new(10.0, -20.0, Some(4326));
361 or_panic!(client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&point]));
362 let result = or_panic!(client.query("SELECT geom=ST_GeomFromEWKT('SRID=4326;POINT(10 -20)') FROM geomtests", &[]));
363 assert!(result.iter().map(|r| r.get::<_, bool>(0)).last().unwrap());
364 or_panic!(client.execute("TRUNCATE geomtests", &[]));
365
366 let mut client = connect();
367 or_panic!(client.execute("CREATE TEMPORARY TABLE geomtests (geom geometry(Point, 4326))", &[]));
368
369 let point = ewkb::Point::new(10.0, -20.0, Some(4326));
370 or_panic!(client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&point]));
371 let result = or_panic!(client.query("SELECT geom=ST_GeomFromEWKT('SRID=4326;POINT(10 -20)') FROM geomtests", &[]));
372 assert!(result.iter().map(|r| r.get::<_, bool>(0)).last().unwrap());
373 or_panic!(client.execute("TRUNCATE geomtests", &[]));
374
375 let point = ewkb::Point::new(10.0, -20.0, None);
377 let result = client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&point]);
378 assert!(format!("{}", result.err().unwrap()).starts_with("db error"));
379 }
380
381 #[test]
382 #[ignore]
383 #[rustfmt::skip]
384 fn test_insert_line() {
385 let mut client = connect();
386 or_panic!(client.execute("CREATE TEMPORARY TABLE geomtests (geom geometry(LineString))", &[]));
387
388 let p = |x, y| ewkb::Point::new(x, y, None);
389 let line = ewkb::LineString {srid: None, points: vec![p(10.0, -20.0), p(0., -0.5)]};
391 or_panic!(client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&line]));
392 let result = or_panic!(client.query("SELECT geom=ST_GeomFromEWKT('LINESTRING(10 -20, 0 -0.5)') FROM geomtests", &[]));
393 assert!(result.iter().map(|r| r.get::<_, bool>(0)).last().unwrap());
394 or_panic!(client.execute("TRUNCATE geomtests", &[]));
395
396 let mut client = connect();
397 or_panic!(client.execute("CREATE TEMPORARY TABLE geomtests (geom geometry(LineString, 4326))", &[]));
398
399 let line = ewkb::LineString {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]};
401 or_panic!(client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&line]));
402 let result = or_panic!(client.query("SELECT geom=ST_GeomFromEWKT('SRID=4326;LINESTRING(10 -20, 0 -0.5)') FROM geomtests", &[]));
403 assert!(result.iter().map(|r| r.get::<_, bool>(0)).last().unwrap());
404 or_panic!(client.execute("TRUNCATE geomtests", &[]));
405
406 let mut client = connect();
407 or_panic!(client.execute("CREATE TEMPORARY TABLE geomtests (geom geometry(LineStringZ, 4326))", &[]));
408
409 let p = |x, y, z| ewkb::PointZ { x, y, z, srid: Some(4326) };
410 let line = ewkb::LineStringZ {srid: Some(4326), points: vec![p(10.0, -20.0, 100.0), p(0., -0.5, 101.0)]};
412 or_panic!(client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&line]));
413 let result = or_panic!(client.query("SELECT geom=ST_GeomFromEWKT('SRID=4326;LINESTRING (10 -20 100, 0 -0.5 101)') FROM geomtests", &[]));
414 assert!(result.iter().map(|r| r.get::<_, bool>(0)).last().unwrap());
415 or_panic!(client.execute("TRUNCATE geomtests", &[]));
416 }
417
418 #[test]
419 #[ignore]
420 #[rustfmt::skip]
421 fn test_insert_polygon() {
422 let mut client = connect();
423 or_panic!(client.execute("CREATE TEMPORARY TABLE geomtests (geom geometry(Polygon))", &[]));
424 let p = |x, y| ewkb::Point::new(x, y, Some(4326));
425 let line = ewkb::LineString {srid: Some(4326), points: vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]};
427 let poly = ewkb::Polygon {srid: Some(4326), rings: vec![line]};
428 or_panic!(client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&poly]));
429 let result = or_panic!(client.query("SELECT geom=ST_GeomFromEWKT('SRID=4326;POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))') FROM geomtests", &[]));
430 assert!(result.iter().map(|r| r.get::<_, bool>(0)).last().unwrap());
431 }
432
433 #[test]
434 #[ignore]
435 #[rustfmt::skip]
436 fn test_insert_multipoint() {
437 let mut client = connect();
438 or_panic!(client.execute("CREATE TEMPORARY TABLE geomtests (geom geometry(MultiPointZ))", &[]));
439 let p = |x, y, z| ewkb::PointZ { x, y, z, srid: Some(4326) };
440 let points = ewkb::MultiPointZ {srid: Some(4326), points: vec![p(10.0, -20.0, 100.0), p(0., -0.5, 101.0)]};
442 or_panic!(client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&points]));
443 let result = or_panic!(client.query("SELECT geom=ST_GeomFromEWKT('SRID=4326;MULTIPOINT ((10 -20 100), (0 -0.5 101))') FROM geomtests", &[]));
444 assert!(result.iter().map(|r| r.get::<_, bool>(0)).last().unwrap());
445 }
446
447 #[test]
448 #[ignore]
449 #[rustfmt::skip]
450 fn test_insert_multiline() {
451 let mut client = connect();
452 or_panic!(client.execute("CREATE TEMPORARY TABLE geomtests (geom geometry(MultiLineString))", &[]));
453 let p = |x, y| ewkb::Point::new(x, y, Some(4326));
454 let line1 = ewkb::LineString {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]};
456 let line2 = ewkb::LineString {srid: Some(4326), points: vec![p(0., 0.), p(2., 0.)]};
457 let multiline = ewkb::MultiLineString {srid: Some(4326),lines: vec![line1, line2]};
458 or_panic!(client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&multiline]));
459 let result = or_panic!(client.query("SELECT geom=ST_GeomFromEWKT('SRID=4326;MULTILINESTRING ((10 -20, 0 -0.5), (0 0, 2 0))') FROM geomtests", &[]));
460 assert!(result.iter().map(|r| r.get::<_, bool>(0)).last().unwrap());
461 }
462
463 #[test]
464 #[ignore]
465 #[rustfmt::skip]
466 fn test_insert_multipolygon() {
467 let mut client = connect();
468 or_panic!(client.execute("CREATE TEMPORARY TABLE geomtests (geom geometry(MultiPolygon))", &[]));
469 let p = |x, y| ewkb::Point::new(x, y, Some(4326));
470 let line = ewkb::LineString {srid: Some(4326), points: vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]};
472 let poly1 = ewkb::Polygon {srid: Some(4326), rings: vec![line]};
473 let line = ewkb::LineString {srid: Some(4326), points: vec![p(10., 10.), p(-2., 10.), p(-2., -2.), p(10., -2.), p(10., 10.)]};
474 let poly2 = ewkb::Polygon {srid: Some(4326), rings: vec![line]};
475 let multipoly = ewkb::MultiPolygon {srid: Some(4326), polygons: vec![poly1, poly2]};
476 or_panic!(client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&multipoly]));
477 let result = or_panic!(client.query("SELECT geom=ST_GeomFromEWKT('SRID=4326;MULTIPOLYGON (((0 0, 2 0, 2 2, 0 2, 0 0)), ((10 10, -2 10, -2 -2, 10 -2, 10 10)))') FROM geomtests", &[]));
478 assert!(result.iter().map(|r| r.get::<_, bool>(0)).last().unwrap());
479 }
480
481 #[test]
482 #[ignore]
483 #[rustfmt::skip]
484 fn test_insert_geometry() {
485 let mut client = connect();
486 or_panic!(client.execute("CREATE TEMPORARY TABLE geomtests (geom geometry)", &[]));
487 let p = |x, y| ewkb::Point::new(x, y, Some(4326));
488 let multipoly = {
490 let line = ewkb::LineString {srid: Some(4326), points: vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]};
491 let poly1 = ewkb::Polygon {srid: Some(4326), rings: vec![line]};
492 let line = ewkb::LineString {srid: Some(4326), points: vec![p(10., 10.), p(-2., 10.), p(-2., -2.), p(10., -2.), p(10., 10.)]};
493 let poly2 = ewkb::Polygon {srid: Some(4326), rings: vec![line]};
494 ewkb::MultiPolygon {srid: Some(4326), polygons: vec![poly1, poly2]}
495 };
496 let geometry = ewkb::GeometryT::MultiPolygon(multipoly);
497 or_panic!(client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&geometry]));
498 let result = or_panic!(client.query("SELECT geom=ST_GeomFromEWKT('SRID=4326;MULTIPOLYGON (((0 0, 2 0, 2 2, 0 2, 0 0)), ((10 10, -2 10, -2 -2, 10 -2, 10 10)))') FROM geomtests", &[]));
499 assert!(result.iter().map(|r| r.get::<_, bool>(0)).last().unwrap());
500 }
501
502 #[test]
503 #[ignore]
504 #[rustfmt::skip]
505 fn test_insert_geometrycollection() {
506 let mut client = connect();
507 or_panic!(client.execute("CREATE TEMPORARY TABLE geomtests (geom geometry(GeometryCollection))", &[]));
508 let p = |x, y| ewkb::Point::new(x, y, Some(4326));
509 let line = ewkb::LineString {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]};
511 let multipoly = {
513 let line = ewkb::LineString {srid: Some(4326), points: vec![p(0., 0.), p(2., 0.), p(2., 2.), p(0., 2.), p(0., 0.)]};
514 let poly1 = ewkb::Polygon {srid: Some(4326), rings: vec![line]};
515 let line = ewkb::LineString {srid: Some(4326), points: vec![p(10., 10.), p(-2., 10.), p(-2., -2.), p(10., -2.), p(10., 10.)]};
516 let poly2 = ewkb::Polygon {srid: Some(4326), rings: vec![line]};
517 ewkb::MultiPolygon {srid: Some(4326), polygons: vec![poly1, poly2]}
518 };
519 let collection = ewkb::GeometryCollection{
521 srid: Some(4326),
522 geometries: vec![
523 ewkb::GeometryT::LineString(line),
524 ewkb::GeometryT::MultiPolygon(multipoly),
525 ],
526 };
527 or_panic!(client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&collection]));
528 let result = or_panic!(client.query("SELECT geom=ST_GeomFromEWKT('SRID=4326;GEOMETRYCOLLECTION (LINESTRING (10 -20,0 -0.5), MULTIPOLYGON (((0 0,2 0,2 2,0 2,0 0)),((10 10,-2 10,-2 -2,10 -2,10 10))))') FROM geomtests", &[]));
529 assert!(result.iter().map(|r| r.get::<_, bool>(0)).last().unwrap());
530 }
531
532 #[test]
533 #[ignore]
534 #[rustfmt::skip]
535 fn test_select_point() {
536 let mut client = connect();
537 let result = or_panic!(client.query("SELECT ('POINT(10 -20)')::geometry", &[]));
538 let point = result.iter().map(|r| r.get::<_, ewkb::Point>(0)).last().unwrap();
539 let expected = ewkb::Point::new(10.0, -20.0, None);
540 assert_eq!(point.x(), expected.x());
541 assert_eq!(point.y(), expected.y());
542 assert_eq!(point.srid, expected.srid);
543
544 let result = or_panic!(client.query("SELECT 'SRID=4326;POINT(10 -20)'::geometry", &[]));
545 let point = result.iter().map(|r| r.get::<_, ewkb::Point>(0)).last().unwrap();
546 let expected = ewkb::Point::new(10.0, -20.0, Some(4326));
547 assert_eq!(point.x(), expected.x());
548 assert_eq!(point.y(), expected.y());
549 assert_eq!(point.srid, expected.srid);
550
551 let result = or_panic!(client.query("SELECT 'SRID=4326;POINT(10 -20 99)'::geometry", &[]));
552 let point = result.iter().map(|r| r.get::<_, ewkb::PointZ>(0)).last().unwrap();
553 assert_eq!(point, ewkb::PointZ { x: 10.0, y: -20.0, z: 99.0, srid: Some(4326) });
554
555 let result = or_panic!(client.query("SELECT 'POINT EMPTY'::geometry", &[]));
556 let point = result.iter().map(|r| r.get::<_, ewkb::Point>(0)).last().unwrap();
557 assert_eq!(&format!("{:?}", point), "Point { x: NaN, y: NaN, srid: None }");
558
559 let result = or_panic!(client.query("SELECT NULL::geometry(Point)", &[]));
560 let point = result.iter().map(|r| r.try_get::<_, ewkb::Point>(0)).last().unwrap();
561 assert_eq!(&format!("{:?}", point), "Err(Error { kind: FromSql(0), cause: Some(WasNull) })");
562 }
563
564 #[test]
565 #[ignore]
566 #[rustfmt::skip]
567 fn test_select_line() {
568 let mut client = connect();
569 let p = |x, y| ewkb::Point::new(x, y, None);
570 let result = or_panic!(client.query("SELECT ('LINESTRING (10 -20, -0 -0.5)')::geometry", &[]));
571 let line = result.iter().map(|r| r.get::<_, ewkb::LineString>(0)).last().unwrap();
572 assert_eq!(line, ewkb::LineString {srid: None, points: vec![p(10.0, -20.0), p(0., -0.5)]});
573
574 let p = |x, y| ewkb::Point::new(x, y, Some(4326));
575 let result = or_panic!(client.query("SELECT ('SRID=4326;LINESTRING (10 -20, -0 -0.5)')::geometry", &[]));
576 let line = result.iter().map(|r| r.get::<_, ewkb::LineString>(0)).last().unwrap();
577 assert_eq!(line, ewkb::LineString {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]});
578
579 let p = |x, y| ewkb::Point::new(x, y, Some(4326));
580 let result = or_panic!(client.query("SELECT ('SRID=4326;LINESTRINGZ (10 -20 1, -0 -0.5 1)')::geometry", &[]));
581 let line = result.iter().map(|r| r.get::<_, ewkb::LineString>(0)).last().unwrap();
582 assert_eq!(line, ewkb::LineString {srid: Some(4326), points: vec![p(10.0, -20.0), p(0., -0.5)]});
583
584 let result = or_panic!(client.query("SELECT 'LINESTRING EMPTY'::geometry", &[]));
585 let line = result.iter().map(|r| r.get::<_, ewkb::LineString>(0)).last().unwrap();
586 assert_eq!(&format!("{:?}", line), "LineStringT { points: [], srid: None }");
587 }
588
589 #[test]
590 #[ignore]
591 #[rustfmt::skip]
592 fn test_select_polygon() {
593 let mut client = connect();
594 let result = or_panic!(client.query("SELECT 'SRID=4326;POLYGON ((0 0, 2 0, 2 2, 0 2, 0 0))'::geometry", &[]));
595 let poly = result.iter().map(|r| r.get::<_, ewkb::Polygon>(0)).last().unwrap();
596 assert_eq!(format!("{:.0?}", poly), "PolygonT { rings: [LineStringT { points: [Point { x: 0, y: 0, srid: Some(4326) }, Point { x: 2, y: 0, srid: Some(4326) }, Point { x: 2, y: 2, srid: Some(4326) }, Point { x: 0, y: 2, srid: Some(4326) }, Point { x: 0, y: 0, srid: Some(4326) }], srid: Some(4326) }], srid: Some(4326) }");
597 }
598
599 #[test]
600 #[ignore]
601 #[rustfmt::skip]
602 fn test_select_multipoint() {
603 let mut client = connect();
604 let result = or_panic!(client.query("SELECT 'SRID=4326;MULTIPOINT ((10 -20 100), (0 -0.5 101))'::geometry", &[]));
605 let points = result.iter().map(|r| r.get::<_, ewkb::MultiPointZ>(0)).last().unwrap();
606 assert_eq!(format!("{:.1?}", points), "MultiPointT { points: [PointZ { x: 10.0, y: -20.0, z: 100.0, srid: None }, PointZ { x: 0.0, y: -0.5, z: 101.0, srid: None }], srid: Some(4326) }");
607 }
608
609 #[test]
610 #[ignore]
611 #[rustfmt::skip]
612 fn test_select_multiline() {
613 let mut client = connect();
614 let result = or_panic!(client.query("SELECT 'SRID=4326;MULTILINESTRING ((10 -20, 0 -0.5), (0 0, 2 0))'::geometry", &[]));
615 let multiline = result.iter().map(|r| r.get::<_, ewkb::MultiLineString>(0)).last().unwrap();
616 assert_eq!(format!("{:.1?}", multiline), "MultiLineStringT { lines: [LineStringT { points: [Point { x: 10.0, y: -20.0, srid: None }, Point { x: 0.0, y: -0.5, srid: None }], srid: None }, LineStringT { points: [Point { x: 0.0, y: 0.0, srid: None }, Point { x: 2.0, y: 0.0, srid: None }], srid: None }], srid: Some(4326) }");
617 }
618
619 #[test]
620 #[ignore]
621 #[rustfmt::skip]
622 fn test_select_multipolygon() {
623 let mut client = connect();
624 let result = or_panic!(client.query("SELECT 'SRID=4326;MULTIPOLYGON (((0 0, 2 0, 2 2, 0 2, 0 0)), ((10 10, -2 10, -2 -2, 10 -2, 10 10)))'::geometry", &[]));
625 let multipoly = result.iter().map(|r| r.get::<_, ewkb::MultiPolygon>(0)).last().unwrap();
626 assert_eq!(format!("{:.0?}", multipoly), "MultiPolygonT { polygons: [PolygonT { rings: [LineStringT { points: [Point { x: 0, y: 0, srid: None }, Point { x: 2, y: 0, srid: None }, Point { x: 2, y: 2, srid: None }, Point { x: 0, y: 2, srid: None }, Point { x: 0, y: 0, srid: None }], srid: None }], srid: None }, PolygonT { rings: [LineStringT { points: [Point { x: 10, y: 10, srid: None }, Point { x: -2, y: 10, srid: None }, Point { x: -2, y: -2, srid: None }, Point { x: 10, y: -2, srid: None }, Point { x: 10, y: 10, srid: None }], srid: None }], srid: None }], srid: Some(4326) }");
627 }
628
629 #[test]
630 #[ignore]
631 #[rustfmt::skip]
632 fn test_select_geometrycollection() {
633 let mut client = connect();
634 let result = or_panic!(client.query("SELECT 'GeometryCollection(POINT (10 10),POINT (30 30),LINESTRING (15 15, 20 20))'::geometry", &[]));
635 let geom = result.iter().map(|r| r.get::<_, ewkb::GeometryCollection>(0)).last().unwrap();
636 assert_eq!(format!("{:.0?}", geom), "GeometryCollectionT { geometries: [Point(Point { x: 10, y: 10, srid: None }), Point(Point { x: 30, y: 30, srid: None }), LineString(LineStringT { points: [Point { x: 15, y: 15, srid: None }, Point { x: 20, y: 20, srid: None }], srid: None })], srid: None }");
637 }
638
639 #[test]
640 #[ignore]
641 #[rustfmt::skip]
642 fn test_select_geometry() {
643 let mut client = connect();
644 or_panic!(client.execute("CREATE TEMPORARY TABLE geomtests (geom geometry)", &[]));
645 or_panic!(client.execute("INSERT INTO geomtests VALUES('SRID=4326;POINT(10 -20 99)'::geometry)", &[]));
646 let result = or_panic!(client.query("SELECT geom FROM geomtests", &[]));
647 let geom = result.iter().map(|r| r.get::<_, ewkb::GeometryZ>(0)).last().unwrap();
648 assert_eq!(format!("{:.0?}", geom), "Point(PointZ { x: 10, y: -20, z: 99, srid: Some(4326) })");
649 }
650
651 #[test]
652 #[ignore]
653 #[rustfmt::skip]
654 fn test_select_type_error() {
655 let mut client = connect();
656 let result = or_panic!(client.query("SELECT ('LINESTRING (10 -20, -0 -0.5)')::geometry", &[]));
657 let poly = result.iter().map(|r| r.try_get::<_, ewkb::Polygon>(0)).last().unwrap();
658 assert_eq!(format!("{:?}", poly), "Err(Error { kind: FromSql(0), cause: Some(\"cannot convert geometry to PolygonT\") })");
659 }
660
661 #[test]
662 #[ignore]
663 #[rustfmt::skip]
664 fn test_twkb() {
665 let mut client = connect();
666 let result = or_panic!(client.query("SELECT ST_AsTWKB('POINT(10 -20)'::geometry)", &[]));
667 let point = result.iter().map(|r| r.get::<_, twkb::Point>(0)).last().unwrap();
668 assert_eq!(point, twkb::Point {x: 10.0, y: -20.0});
669
670 let result = or_panic!(client.query("SELECT ST_AsTWKB('SRID=4326;POINT(10 -20)'::geometry)", &[]));
671 let point = result.iter().map(|r| r.get::<_, twkb::Point>(0)).last().unwrap();
672 assert_eq!(point, twkb::Point {x: 10.0, y: -20.0});
673
674 let result = or_panic!(client.query("SELECT ST_AsTWKB('POINT EMPTY'::geometry)", &[]));
675 let point = result.iter().map(|r| r.get::<_, twkb::Point>(0)).last().unwrap();
676 assert_eq!(&format!("{:?}", point), "Point { x: NaN, y: NaN }");
677 let point = &point as &dyn postgis::Point;
678 assert!(point.x().is_nan());
679
680 let result = or_panic!(client.query("SELECT ST_AsTWKB(NULL::geometry(Point))", &[]));
681 let point = result.iter().map(|r| r.try_get::<_, twkb::Point>(0)).last().unwrap();
682 assert_eq!(&format!("{:?}", point), "Err(Error { kind: FromSql(0), cause: Some(WasNull) })");
683
684 let result = or_panic!(client.query("SELECT ST_AsTWKB('LINESTRING (10 -20, -0 -0.5)'::geometry, 1)", &[]));
685 let line = result.iter().map(|r| r.get::<_, twkb::LineString>(0)).last().unwrap();
686 assert_eq!(&format!("{:.1?}", line), "LineString { points: [Point { x: 10.0, y: -20.0 }, Point { x: 0.0, y: -0.5 }] }");
687 }
688
689 #[test]
690 #[ignore]
691 #[rustfmt::skip]
692 fn test_twkb_insert() {
693 let mut client = connect();
694 or_panic!(client.execute("CREATE TEMPORARY TABLE geomtests (geom geometry(Point))", &[]));
695
696 let result = or_panic!(client.query("SELECT ST_AsTWKB('POINT(10 -20)'::geometry)", &[]));
697 let point = result.iter().map(|r| r.get::<_, twkb::Point>(0)).last().unwrap();
698
699 or_panic!(client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&point.as_ewkb()]));
700 let result = or_panic!(client.query("SELECT geom=ST_GeomFromEWKT('POINT(10 -20)') FROM geomtests", &[]));
701 assert!(result.iter().map(|r| r.get::<_, bool>(0)).last().unwrap());
702 or_panic!(client.execute("TRUNCATE geomtests", &[]));
703
704 let mut client = connect();
705 or_panic!(client.execute("CREATE TEMPORARY TABLE geomtests (geom geometry(LineString))", &[]));
706
707 let result = or_panic!(client.query("SELECT ST_AsTWKB('LINESTRING (10 -20, 0 -0.5)'::geometry, 1)", &[]));
708 let line = result.iter().map(|r| r.get::<_, twkb::LineString>(0)).last().unwrap();
709
710 or_panic!(client.execute("INSERT INTO geomtests (geom) VALUES ($1)", &[&line.as_ewkb()]));
711 let result = or_panic!(client.query("SELECT geom=ST_GeomFromEWKT('LINESTRING (10 -20, 0 -0.5)') FROM geomtests", &[]));
712 assert!(result.iter().map(|r| r.get::<_, bool>(0)).last().unwrap());
713 or_panic!(client.execute("TRUNCATE geomtests", &[]));
714 }
715
716 #[test]
717 #[ignore]
718 #[rustfmt::skip]
719 #[allow(unused_imports,unused_variables)]
720 fn test_examples() {
721 use postgres::{Client, NoTls};
722 fn main() {
726 use crate::{
728 ewkb,
729 types::LineString,
730 twkb
731 };
732 let mut client = connect();
733 or_panic!(client.execute("CREATE TEMPORARY TABLE busline (route geometry(LineString))", &[]));
734 or_panic!(client.execute("CREATE TEMPORARY TABLE stops (stop geometry(Point))", &[]));
735 or_panic!(client.execute("INSERT INTO busline (route) VALUES ('LINESTRING(10 -20, -0 -0.5)'::geometry)", &[]));
736 for row in &client.query("SELECT * FROM busline", &[]).unwrap() {
740 let route: ewkb::LineString = row.get("route");
741 let last_stop = route.points().last().unwrap();
742 let _ = client.execute("INSERT INTO stops (stop) VALUES ($1)", &[&last_stop]);
743 }
744
745 for row in &client.query("SELECT * FROM busline", &[]).unwrap() {
746 let route = row.try_get::<_, Option<ewkb::LineString>>("route");
747 match route {
748 Ok(Some(geom)) => { println!("{:?}", geom) }
749 Ok(None) => { }
750 Err(err) => { println!("Error: {}", err) }
751 }
752 }
753
754 for row in &client.query("SELECT ST_AsTWKB(route) FROM busline", &[]).unwrap() {
757 let route: twkb::LineString = row.get(0);
758 let last_stop = route.points().last().unwrap();
759 let _ = client.execute("INSERT INTO stops (stop) VALUES ($1)", &[&last_stop.as_ewkb()]);
760 }
761 }
762
763 main();
764 }
765}