From c0d5aace54f95874b4b0ae2e0a782b6385d97cc1 Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Tue, 3 Jan 2023 17:52:22 +0000 Subject: [PATCH] Allow trailing commas in SQL Geometry types Closes #1523 --- lib/src/sql/geometry.rs | 89 +++++++++++++++++++++++++++++++++-------- lib/tests/geometry.rs | 88 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 157 insertions(+), 20 deletions(-) diff --git a/lib/src/sql/geometry.rs b/lib/src/sql/geometry.rs index f3ebf0a3..549658de 100644 --- a/lib/src/sql/geometry.rs +++ b/lib/src/sql/geometry.rs @@ -12,6 +12,7 @@ use geo::{MultiLineString, MultiPoint, MultiPolygon}; use nom::branch::alt; use nom::bytes::complete::tag; use nom::character::complete::char; +use nom::combinator::opt; use nom::multi::separated_list0; use nom::multi::separated_list1; use nom::number::complete::double; @@ -591,9 +592,7 @@ fn simple(i: &str) -> IResult<&str, Geometry> { let (i, _) = char('(')(i)?; let (i, _) = mightbespace(i)?; let (i, x) = double(i)?; - let (i, _) = mightbespace(i)?; - let (i, _) = char(',')(i)?; - let (i, _) = mightbespace(i)?; + let (i, _) = commas(i)?; let (i, y) = double(i)?; let (i, _) = mightbespace(i)?; let (i, _) = char(')')(i)?; @@ -606,14 +605,20 @@ fn point(i: &str) -> IResult<&str, Geometry> { let (i, v) = alt(( |i| { let (i, _) = preceded(key_type, point_type)(i)?; - let (i, _) = delimited(mightbespace, char(','), mightbespace)(i)?; + let (i, _) = commas(i)?; let (i, v) = preceded(key_vals, point_vals)(i)?; + let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; Ok((i, v)) }, |i| { let (i, v) = preceded(key_vals, point_vals)(i)?; - let (i, _) = delimited(mightbespace, char(','), mightbespace)(i)?; + let (i, _) = commas(i)?; let (i, _) = preceded(key_type, point_type)(i)?; + let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; Ok((i, v)) }, ))(i)?; @@ -628,14 +633,20 @@ fn line(i: &str) -> IResult<&str, Geometry> { let (i, v) = alt(( |i| { let (i, _) = preceded(key_type, line_type)(i)?; - let (i, _) = delimited(mightbespace, char(','), mightbespace)(i)?; + let (i, _) = commas(i)?; let (i, v) = preceded(key_vals, line_vals)(i)?; + let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; Ok((i, v)) }, |i| { let (i, v) = preceded(key_vals, line_vals)(i)?; - let (i, _) = delimited(mightbespace, char(','), mightbespace)(i)?; + let (i, _) = commas(i)?; let (i, _) = preceded(key_type, line_type)(i)?; + let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; Ok((i, v)) }, ))(i)?; @@ -650,14 +661,20 @@ fn polygon(i: &str) -> IResult<&str, Geometry> { let (i, v) = alt(( |i| { let (i, _) = preceded(key_type, polygon_type)(i)?; - let (i, _) = delimited(mightbespace, char(','), mightbespace)(i)?; + let (i, _) = commas(i)?; let (i, v) = preceded(key_vals, polygon_vals)(i)?; + let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; Ok((i, v)) }, |i| { let (i, v) = preceded(key_vals, polygon_vals)(i)?; - let (i, _) = delimited(mightbespace, char(','), mightbespace)(i)?; + let (i, _) = commas(i)?; let (i, _) = preceded(key_type, polygon_type)(i)?; + let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; Ok((i, v)) }, ))(i)?; @@ -672,14 +689,20 @@ fn multipoint(i: &str) -> IResult<&str, Geometry> { let (i, v) = alt(( |i| { let (i, _) = preceded(key_type, multipoint_type)(i)?; - let (i, _) = delimited(mightbespace, char(','), mightbespace)(i)?; + let (i, _) = commas(i)?; let (i, v) = preceded(key_vals, multipoint_vals)(i)?; + let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; Ok((i, v)) }, |i| { let (i, v) = preceded(key_vals, multipoint_vals)(i)?; - let (i, _) = delimited(mightbespace, char(','), mightbespace)(i)?; + let (i, _) = commas(i)?; let (i, _) = preceded(key_type, multipoint_type)(i)?; + let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; Ok((i, v)) }, ))(i)?; @@ -694,14 +717,20 @@ fn multiline(i: &str) -> IResult<&str, Geometry> { let (i, v) = alt(( |i| { let (i, _) = preceded(key_type, multiline_type)(i)?; - let (i, _) = delimited(mightbespace, char(','), mightbespace)(i)?; + let (i, _) = commas(i)?; let (i, v) = preceded(key_vals, multiline_vals)(i)?; + let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; Ok((i, v)) }, |i| { let (i, v) = preceded(key_vals, multiline_vals)(i)?; - let (i, _) = delimited(mightbespace, char(','), mightbespace)(i)?; + let (i, _) = commas(i)?; let (i, _) = preceded(key_type, multiline_type)(i)?; + let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; Ok((i, v)) }, ))(i)?; @@ -716,14 +745,20 @@ fn multipolygon(i: &str) -> IResult<&str, Geometry> { let (i, v) = alt(( |i| { let (i, _) = preceded(key_type, multipolygon_type)(i)?; - let (i, _) = delimited(mightbespace, char(','), mightbespace)(i)?; + let (i, _) = commas(i)?; let (i, v) = preceded(key_vals, multipolygon_vals)(i)?; + let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; Ok((i, v)) }, |i| { let (i, v) = preceded(key_vals, multipolygon_vals)(i)?; - let (i, _) = delimited(mightbespace, char(','), mightbespace)(i)?; + let (i, _) = commas(i)?; let (i, _) = preceded(key_type, multipolygon_type)(i)?; + let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; Ok((i, v)) }, ))(i)?; @@ -738,14 +773,20 @@ fn collection(i: &str) -> IResult<&str, Geometry> { let (i, v) = alt(( |i| { let (i, _) = preceded(key_type, collection_type)(i)?; - let (i, _) = delimited(mightbespace, char(','), mightbespace)(i)?; + let (i, _) = commas(i)?; let (i, v) = preceded(key_geom, collection_vals)(i)?; + let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; Ok((i, v)) }, |i| { let (i, v) = preceded(key_geom, collection_vals)(i)?; - let (i, _) = delimited(mightbespace, char(','), mightbespace)(i)?; + let (i, _) = commas(i)?; let (i, _) = preceded(key_type, collection_type)(i)?; + let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; Ok((i, v)) }, ))(i)?; @@ -768,6 +809,8 @@ fn line_vals(i: &str) -> IResult<&str, LineString> { let (i, _) = mightbespace(i)?; let (i, v) = separated_list1(commas, coordinate)(i)?; let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; let (i, _) = char(']')(i)?; Ok((i, v.into())) } @@ -777,12 +820,16 @@ fn polygon_vals(i: &str) -> IResult<&str, Polygon> { let (i, _) = mightbespace(i)?; let (i, e) = line_vals(i)?; let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; let (i, _) = char(']')(i)?; let (i, v) = separated_list0(commas, |i| { let (i, _) = char('[')(i)?; let (i, _) = mightbespace(i)?; let (i, v) = line_vals(i)?; let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; let (i, _) = char(']')(i)?; Ok((i, v)) })(i)?; @@ -794,6 +841,8 @@ fn multipoint_vals(i: &str) -> IResult<&str, Vec>> { let (i, _) = mightbespace(i)?; let (i, v) = separated_list1(commas, point_vals)(i)?; let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; let (i, _) = char(']')(i)?; Ok((i, v)) } @@ -803,6 +852,8 @@ fn multiline_vals(i: &str) -> IResult<&str, Vec>> { let (i, _) = mightbespace(i)?; let (i, v) = separated_list1(commas, line_vals)(i)?; let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; let (i, _) = char(']')(i)?; Ok((i, v)) } @@ -812,6 +863,8 @@ fn multipolygon_vals(i: &str) -> IResult<&str, Vec>> { let (i, _) = mightbespace(i)?; let (i, v) = separated_list1(commas, polygon_vals)(i)?; let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; let (i, _) = char(']')(i)?; Ok((i, v)) } @@ -821,6 +874,8 @@ fn collection_vals(i: &str) -> IResult<&str, Vec> { let (i, _) = mightbespace(i)?; let (i, v) = separated_list1(commas, geometry)(i)?; let (i, _) = mightbespace(i)?; + let (i, _) = opt(char(','))(i)?; + let (i, _) = mightbespace(i)?; let (i, _) = char(']')(i)?; Ok((i, v)) } diff --git a/lib/tests/geometry.rs b/lib/tests/geometry.rs index af430798..cd8c83cf 100644 --- a/lib/tests/geometry.rs +++ b/lib/tests/geometry.rs @@ -58,12 +58,42 @@ async fn geometry_polygon() -> Result<(), Error> { [-0.38314819, 51.37692386] ]] }; + UPDATE city:london SET area = { + type: 'Polygon', + coordinates: [[ + [-0.38314819, 51.37692386], [0.1785278, 51.37692386], + [0.1785278, 51.61460570], [-0.38314819, 51.61460570], + [-0.38314819, 51.37692386], + ]], + }; SELECT * FROM city:london; "; let dbs = Datastore::new("memory").await?; let ses = Session::for_kv().with_ns("test").with_db("test"); let res = &mut dbs.execute(&sql, &ses, None, false).await?; - assert_eq!(res.len(), 2); + assert_eq!(res.len(), 3); + // + let tmp = res.remove(0).result?; + let val = Value::parse( + r#"[ + { + "area": { + "type": "Polygon", + "coordinates": [ + [ + [-0.38314819, 51.37692386], + [0.1785278, 51.37692386], + [0.1785278, 51.6146057], + [-0.38314819, 51.6146057], + [-0.38314819, 51.37692386] + ] + ] + }, + "id": "city:london" + } + ]"#, + ); + assert_eq!(tmp, val); // let tmp = res.remove(0).result?; let val = Value::parse( @@ -122,12 +152,36 @@ async fn geometry_multipoint() -> Result<(), Error> { [-0.118092, 51.509865] ] }; + UPDATE city:london SET points = { + type: 'MultiPoint', + coordinates: [ + [-0.118092, 51.509865], + [-0.118092, 51.509865], + ], + }; SELECT * FROM city:london; "; let dbs = Datastore::new("memory").await?; let ses = Session::for_kv().with_ns("test").with_db("test"); let res = &mut dbs.execute(&sql, &ses, None, false).await?; - assert_eq!(res.len(), 2); + assert_eq!(res.len(), 3); + // + let tmp = res.remove(0).result?; + let val = Value::parse( + r#"[ + { + "points": { + "type": "MultiPoint", + "coordinates": [ + [-0.118092, 51.509865], + [-0.118092, 51.509865] + ] + }, + "id": "city:london" + } + ]"#, + ); + assert_eq!(tmp, val); // let tmp = res.remove(0).result?; let val = Value::parse( @@ -176,12 +230,40 @@ async fn geometry_multipolygon() -> Result<(), Error> { [[ [9.0, 11.2], [10.5, 11.9], [10.3, 13.0], [9.0, 11.2] ]] ] }; + UPDATE university:oxford SET area = { + type: 'MultiPolygon', + coordinates: [ + [[ [10.0, 11.2], [10.5, 11.9], [10.8, 12.0], [10.0, 11.2] ]], + [[ [9.0, 11.2], [10.5, 11.9], [10.3, 13.0], [9.0, 11.2] ]], + ], + }; SELECT * FROM university:oxford; "; let dbs = Datastore::new("memory").await?; let ses = Session::for_kv().with_ns("test").with_db("test"); let res = &mut dbs.execute(&sql, &ses, None, false).await?; - assert_eq!(res.len(), 2); + assert_eq!(res.len(), 3); + // + let tmp = res.remove(0).result?; + let val = Value::parse( + r#"[ + { + "area": { + "type": "MultiPolygon", + "coordinates": [ + [ + [[10.0, 11.2], [10.5, 11.9], [10.8, 12.0], [10.0, 11.2]] + ], + [ + [[9.0, 11.2], [10.5, 11.9], [10.3, 13.0], [9.0, 11.2]] + ] + ] + }, + "id": "university:oxford" + } + ]"#, + ); + assert_eq!(tmp, val); // let tmp = res.remove(0).result?; let val = Value::parse(