8000 Merge pull request #30 from Mernus/feature/add-geo-types · psqlpy-python/psqlpy@cad337e · GitHub
[go: up one dir, main page]

Skip to content

Commit cad337e

Browse files
authored
Merge pull request #30 from Mernus/feature/add-geo-types
Added support for Geometric Types (except Polygon)
2 parents ac92908 + 4d8085a commit cad337e

File tree

10 files changed

+1675
-256
lines changed

10 files changed

+1675
-256
lines changed

Cargo.lock

Lines changed: 250 additions & 230 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ byteorder = "1.5.0"
2525
chrono = "0.4.33"
2626
chrono-tz = "0.8.5"
2727
uuid = { version = "1.7.0", features = ["v4"] }
28+
serde = { version = "1.0.205", features = ["derive"] }
2829
serde_json = "1.0.113"
2930
futures-util = "0.3.30"
3031
macaddr = "1.0.1"
32+
geo-types = "0.7.13"
3133
postgres-types = { git = "https://github.com/chandr-andr/rust-postgres.git", branch = "psqlpy", features = [
3234
"derive",
3335
] }
@@ -36,6 +38,7 @@ tokio-postgres = { git = "https://github.com/chandr-andr/rust-postgres.git", bra
3638
"array-impls",
3739
"with-chrono-0_4",
3840
"with-uuid-1",
41+
"with-geo-types-0_7",
3942
] }
4043
postgres-protocol = { git = "https://github.com/chandr-andr/rust-postgres.git", branch = "psqlpy" }
4144
postgres-openssl = { git = "https://github.com/chandr-andr/rust-postgres.git", branch = "psqlpy" }
@@ -44,3 +47,4 @@ rust_decimal = { git = "https://github.com/chandr-andr/rust-decimal.git", branch
4447
"db-tokio-postgres",
4548
] }
4649
openssl = { version = "0.10.64", features = ["vendored"] }
50+
itertools = "0.12.1"

docs/usage/types/extra_types.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ All extra types available from Python with mapping to PostgreSQL type and Rust t
1818
| PyJSONB | JSONB | serde::Value |
1919
| PyMacAddr6 | MacAddr | MacAddr6 |
2020
| PyMacAddr8 | MacAddr8 | MacAddr8 |
21+
| PyPoint | Point | Point |
22+
| PyBox | Rect | Box |
23+
| PyPath | LineString | Path |
24+
| PyLine | LineSegment | Line |
25+
| PyLineSegment | LineSegment | Lseg |
26+
| PyCircle | Circle | Circle |
27+
2128

2229
## BigInt & Integer & SmallInt & Float32 & Float64
2330
When integer is passed from Python to Rust, it's impossible to understand what type is required on the Database side.
@@ -177,3 +184,43 @@ async def main() -> None:
177184

178185
db_pool.close()
179186
```
187+
188+
## Geo Types
189+
Also in package exists support of PostgreSQL geo types(except Polygon for now).
190+
To use geo types you need specify them directly.
191+
192+
Let's assume we have table `geo_info` with all PostgreSQL geo types in the database:
193+
| database type | database column name |
194+
| :---: | :---: |
195+
| POINT | map_point |
196+
| BOX | point_district |
197+
| PATH | path_to_point |
198+
| LINE | points_line |
199+
| LSEG | lseg_between_points |
200+
| CIRCLE | point_radius_circle |
201+
202+
```python
203+
from typing import Final
204+
205+
from psqlpy import ConnectionPool, QueryResult
206+
from psqlpy.extra_types import PyPoint, PyBox, PyPath, PyLine, PyLineSegment, PyCircle
207+
208+
209+
async def main() -> None:
210+
# It uses default connection parameters
211+
db_pool: Final = ConnectionPool()
212+
213+
await db_pool.execute(
214+
"INSERT INTO geo_info VALUES ($1, $2, $3, $4, $5, $6)",
215+
[
216+
PyPoint([1.5, 2]),
217+
PyBox([(1.7, 2.8), (9, 9)]),
218+
PyPath([(3.5, 3), (9, 9), (8, 8)]),
219+
PyLine([1, -2, 3]),
220+
PyLineSegment([(5.6, 3.1), (4, 5)]),
221+
PyCircle([5, 1.8, 10]),
222+
],
223+
)
224+
225+
db_pool.close()
226+
```

docs/usage/types/supported_types.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Here you can find all types supported by `PSQLPy`. If PSQLPy isn't `-`, you can
1818
| int | INTEGER | INTEGER |
1919
| int | - | INTEGER |
2020
| int | BIGINT | BIGINT |
21-
| float | - | FLOAT4 |
21+
| float | - | FLOAT8 |
2222
| float | Float32 | FLOAT4 |
2323
| float | Float64 | FLOAT8 |
2424
| datetime.date | - | DATE |

python/psqlpy/_internal/extra_types.pyi

Lines changed: 112 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, Union
1+
import typing
22

33
from typing_extensions import Self
44

@@ -91,9 +91,9 @@ class PyJSONB:
9191

9292
def __init__(
9393
self: Self,
94-
value: Union[
95-
dict[str, Any],
96-
list[dict[str, Any]],
94+
value: typing.Union[
95+
dict[str, typing.Any],
96+
list[dict[str, typing.Any]],
9797
],
9898
) -> None:
9999
"""Create new instance of PyJSON.B.
@@ -109,9 +109,9 @@ class PyJSON:
109109

110110
def __init__(
111111
self: Self,
112-
value: Union[
113-
dict[str, Any],
114-
list[dict[str, Any]],
112+
value: typing.Union[
113+
dict[str, typing.Any],
114+
list[dict[str, typing.Any]],
115115
],
116116
) -> None:
117117
"""Create new instance of PyJSON.
@@ -144,3 +144,108 @@ class PyMacAddr8:
144144

145145
class PyCustomType:
146146
def __init__(self, value: bytes) -> None: ...
147+
148+
Coordinates: typing.TypeAlias = typing.Union[
149+
list[int | float],
150+
set[int | float],
151+
tuple[int | float, int | float],
152+
]
153+
PairsOfCoordinates: typing.TypeAlias = typing.Union[
154+
list[Coordinates | int | float],
155+
set[Coordinates | int | float],
156+
tuple[Coordinates | int | float, ...],
157+
]
158+
159+
class PyPoint:
160+
"""Represent point field in PostgreSQL and Point in Rust."""
161+
162+
def __init__(self: Self, value: Coordinates) -> None:
163+
"""Create new instance of PyPoint.
164+
165+
It accepts any pair(List, Tuple or Set)
166+
of int/float numbers in every combination.
167+
168+
### Parameters:
169+
- `value`: pair of int/float numbers in every combination.
170+
"""
171+
172+
class PyBox:
173+
"""Represent box field in PostgreSQL and Rect in Rust."""
174+
175+
def __init__(self: Self, value: PairsOfCoordinates) -> None:
176+
"""Create new instance of PyBox.
177+
178+
You need to pass any of this structures:
179+
- sequence(List, Tuple or Set) of two sequences(List, Tuple or Set),
180+
each with pair of int/float numbers in every combination
181+
- sequence(List, Tuple or Set) of two pairs of int/float in every combination
182+
183+
### Parameters:
184+
- `value`: any valid sequence(List, Tuple or Set) with two pairs
185+
of int/float numbers in every combination.
186+
"""
187+
188+
class PyPath:
189+
"""Represent path field in PostgreSQL and LineString in Rust."""
190+
191+
def __init__(self: Self, value: PairsOfCoordinates) -> None:
192+
"""Create new instance of PyPath.
193+
194+
You need to pass any of this structures:
195+
- sequence(List, Tuple or Set) of sequences(List, Tuple or Set),
196+
each with pair of int/float numbers in every combination
197+
- sequence(List, Tuple or Set) with pairs
198+
of int/float numbers in every combination
199+
200+
### Parameters:
201+
- `value`: any valid structure with int/float numbers in every combination.
202+
"""
203+
204+
class PyLine:
205+
"""Represent line field in PostgreSQL and LineSegment in Rust."""
206+
207+
def __init__(self: Self, value: PairsOfCoordinates) -> None:
208+
"""Create new instance of PyLine.
209+
210+
You need to pass any of this structures:
211+
- sequence of three int/float numbers(a, b, c)
212+
213+
### Parameters:
214+
- `value`: any valid structure with int/float numbers.
215+
"""
216+
217+
class PyLineSegment:
218+
"""Represent lseg field in PostgreSQL and LineSegment in Rust."""
219+
220+
def __init__(self: Self, value: PairsOfCoordinates) -> None:
221+
"""Create new instance of PyLineSegment.
222+
223+
You need to pass any of this structures:
224+
- sequence(List, Tuple or Set) of two sequences(List, Tuple or Set),
225+
each with pair of int/float numbers in every combination
226+
- sequence(List, Tuple or Set) with two pairs
227+
of int/float numbers in every combination
228+
229+
### Parameters:
230+
- `value`: any valid structure with int/float numbers in every combination.
231+
"""
232+
233+
class PyCircle:
234+
"""Represent circle field in PostgreSQL and Circle in Rust."""
235+
236+
def __init__(
237+
self: Self,
238+
value: typing.Union[
239+
list[int | float],
240+
set[int | float],
241+
tuple[int | float, int | float, int | float],
242+
],
243+
) -> None:
244+
"""Create new instance of PyCircle.
245+
246+
You need to pass any of this structures:
247+
- sequence of three int/float numbers(x, y, r)
248+
249+
### Parameters:
250+
- `value`: any valid structure with int/float numbers.
251+
"""

python/psqlpy/extra_types.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,17 @@
44
Float64,
55
Integer,
66
Money,
7+
PyBox,
8+
PyCircle,
79
PyCustomType,
810
PyJSON,
911
PyJSONB,
12+
PyLine,
13+
PyLineSegment,
1014
PyMacAddr6,
1115
PyMacAddr8,
16+
PyPath,
17+
PyPoint,
1218
PyText,
1319
PyVarChar,
1420
SmallInt,
@@ -28,4 +34,10 @@
2834
"Float32",
2935
"Float64",
3036
"Money",
37+
"PyPoint",
38+
"PyBox",
39+
"PyPath",
40+
"PyLine",
41+
"PyLineSegment",
42+
"PyCircle",
3143
]

0 commit comments

Comments
 (0)
0