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