Skip to content

Commit 8346115

Browse files
C-Loftuswebb-ben
andauthored
MySQL OAF provider (#2004)
* Mysql Provider (#6) - mysql provider and associated tests - refactor postgres and mysql to use a shared base class that they both inherit from - handle geometry / encoding necessary to use mysql wity sqlalchemy --------- Co-authored-by: Benjamin Webb <40066515+webb-ben@users.noreply.github.com> * keep postgis instructions * Apply suggestions from code review Co-authored-by: Benjamin Webb <40066515+webb-ben@users.noreply.github.com> * Update pygeoapi/provider/sql.py Co-authored-by: Benjamin Webb <40066515+webb-ben@users.noreply.github.com> * Update pygeoapi/provider/sql.py Co-authored-by: Benjamin Webb <40066515+webb-ben@users.noreply.github.com> * Fix MVT_postgres import * Set default port for Postgres and MySQL provider * Add MySQL documentation * Fix typo --------- Co-authored-by: Benjamin Webb <40066515+webb-ben@users.noreply.github.com> Co-authored-by: Benjamin Webb <benjamin.miller.webb@gmail.com>
1 parent dfe70bb commit 8346115

File tree

10 files changed

+522
-102
lines changed

10 files changed

+522
-102
lines changed

.github/workflows/main.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,17 @@ jobs:
5353
with:
5454
postgresql password: ${{ secrets.DatabasePassword || 'postgres' }}
5555
postgresql db: 'test'
56+
57+
- name: "Install and run MySQL 📦"
58+
uses: mirromutth/mysql-action@v1.1
59+
with:
60+
host port: 3306
61+
mysql version: '8.0'
62+
mysql database: test_geo_app
63+
mysql root password: mysql # This is a dummy password here; not actually used in prod
64+
mysql user: pygeoapi
65+
mysql password: mysql
66+
5667
- name: Install and run Elasticsearch 📦
5768
uses: getong/elasticsearch-action@v1.2
5869
with:
@@ -111,6 +122,7 @@ jobs:
111122
psql postgresql://postgres:${{ secrets.DatabasePassword || 'postgres' }}@localhost:5432/test -f tests/data/dummy_data.sql
112123
psql postgresql://postgres:${{ secrets.DatabasePassword || 'postgres' }}@localhost:5432/test -f tests/data/dummy_types_data.sql
113124
psql postgresql://postgres:${{ secrets.DatabasePassword || 'postgres' }}@localhost:5432/test -f tests/data/postgres_manager_full_structure.backup.sql
125+
mysql -h 127.0.0.1 -P 3306 -u root -p'mysql' test_geo_app < tests/data/mysql_data.sql
114126
docker ps
115127
python3 tests/load_oracle_data.py
116128
- name: run unit tests ⚙️
@@ -142,6 +154,7 @@ jobs:
142154
pytest tests/test_oracle_provider.py
143155
pytest tests/test_parquet_provider.py
144156
pytest tests/test_postgresql_provider.py
157+
pytest tests/test_mysql_provider.py
145158
pytest tests/test_rasterio_provider.py
146159
pytest tests/test_sensorthings_edr_provider.py
147160
pytest tests/test_sensorthings_provider.py

docs/source/data-publishing/ogcapi-features.rst

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ parameters.
2525
`ESRI Feature Service`_,✅/✅,results/hits,✅,✅,✅,✅,❌,❌,❌,✅
2626
`GeoJSON`_,✅/✅,results/hits,❌,❌,❌,✅,❌,❌,❌,✅
2727
`MongoDB`_,✅/❌,results,✅,✅,✅,✅,❌,❌,❌,✅
28+
`MySQL`_,✅/✅,results/hits,✅,✅,✅,✅,❌,✅,✅,✅
2829
`OGR`_,✅/❌,results/hits,✅,❌,❌,✅,❌,❌,❌,✅
2930
`OpenSearch`_,✅/✅,results/hits,✅,✅,✅,✅,❌,✅,✅,✅
3031
`Oracle`_,✅/✅,results/hits,✅,❌,✅,✅,❌,❌,❌,✅
@@ -222,6 +223,76 @@ Here `test` is the name of database , `points` is the target collection name.
222223
data: mongodb://localhost:27017/testdb
223224
collection: testplaces
224225
226+
227+
.. _MySQL:
228+
229+
MySQL
230+
^^^^^
231+
232+
.. note::
233+
Requires Python packages sqlalchemy, geoalchemy2 and pymysql
234+
235+
Must have MySQL installed.
236+
237+
.. code-block:: yaml
238+
239+
providers:
240+
- type: feature
241+
name: MySQL
242+
data:
243+
host: 127.0.0.1
244+
port: 3306 # Default 3306 if not provided
245+
dbname: test_geo_app
246+
user: mysql
247+
password: mysql
248+
search_path: [test_geo_app] # Same as dbname
249+
id_field: locationID
250+
table: location
251+
geom_field: locationCoordinates
252+
253+
A number of database connection options can be also configured in the provider in order to adjust properly the sqlalchemy engine client.
254+
These are optional and if not specified, the default from the engine will be used. Please see also `SQLAlchemy docs <https://docs.sqlalchemy.org/en/14/core/engines.html#custom-dbapi-connect-arguments-on-connect-routines>`_.
255+
256+
.. code-block:: yaml
257+
258+
providers:
259+
- type: feature
260+
name: MySQL
261+
data:
262+
host: 127.0.0.1
263+
port: 3306 # Default 3306 if not provided
264+
dbname: test_geo_app
265+
user: mysql
266+
password: mysql
267+
search_path: [test_geo_app] # Same as dbname
268+
options:
269+
# Maximum time to wait while connecting, in seconds.
270+
connect_timeout: 10
271+
# Number of *milliseconds* that transmitted data may remain
272+
# unacknowledged before a connection is forcibly closed.
273+
tcp_user_timeout: 10000
274+
# Whether client-side TCP keepalives are used. 1 = use keepalives,
275+
# 0 = don't use keepalives.
276+
keepalives: 1
277+
# Number of seconds of inactivity after which TCP should send a
278+
# keepalive message to the server.
279+
keepalives_idle: 5
280+
# Number of TCP keepalives that can be lost before the client's
281+
# connection to the server is considered dead.
282+
keepalives_count: 5
283+
# Number of seconds after which a TCP keepalive message that is not
284+
# acknowledged by the server should be retransmitted.
285+
keepalives_interval: 1
286+
id_field: locationID
287+
table: location
288+
geom_field: locationCoordinates
289+
290+
This provider has support for the CQL queries as indicated in the Provider table above.
291+
292+
.. seealso::
293+
:ref:`cql` for more details on how to use Common Query Language (CQL) to filter the collection with specific queries.
294+
295+
225296
OGR
226297
^^^
227298

pygeoapi/plugin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,13 @@
5353
'MVT-tippecanoe': 'pygeoapi.provider.mvt_tippecanoe.MVTTippecanoeProvider', # noqa: E501
5454
'MVT-elastic': 'pygeoapi.provider.mvt_elastic.MVTElasticProvider',
5555
'MVT-proxy': 'pygeoapi.provider.mvt_proxy.MVTProxyProvider',
56+
'MySQL': 'pygeoapi.provider.sql.MySQLProvider',
5657
'MVT-postgresql': 'pygeoapi.provider.mvt_postgresql.MVTPostgreSQLProvider', # noqa: E501
5758
'OracleDB': 'pygeoapi.provider.oracle.OracleProvider',
5859
'OGR': 'pygeoapi.provider.ogr.OGRProvider',
5960
'OpenSearch': 'pygeoapi.provider.opensearch_.OpenSearchProvider',
6061
'Parquet': 'pygeoapi.provider.parquet.ParquetProvider',
61-
'PostgreSQL': 'pygeoapi.provider.postgresql.PostgreSQLProvider',
62+
'PostgreSQL': 'pygeoapi.provider.sql.PostgreSQLProvider',
6263
'rasterio': 'pygeoapi.provider.rasterio_.RasterioProvider',
6364
'SensorThings': 'pygeoapi.provider.sensorthings.SensorThingsProvider',
6465
'SensorThingsEDR': 'pygeoapi.provider.sensorthings_edr.SensorThingsEDRProvider', # noqa: E501

pygeoapi/process/manager/postgresql.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
ProcessorGenericError
5757
)
5858
from pygeoapi.process.manager.base import BaseManager
59-
from pygeoapi.provider.postgresql import get_engine, get_table_model
59+
from pygeoapi.provider.sql import get_engine, get_table_model
6060
from pygeoapi.util import JobStatus
6161

6262

@@ -92,13 +92,15 @@ def __init__(self, manager_def: dict):
9292
if isinstance(self.connection, str):
9393
_url = make_url(self.connection)
9494
self._engine = get_engine(
95+
'postgresql+psycopg2',
9596
_url.host,
9697
_url.port,
9798
_url.database,
9899
_url.username,
99100
_url.password)
100101
else:
101-
self._engine = get_engine(**self.connection)
102+
self._engine = get_engine('postgresql+psycopg2',
103+
**self.connection)
102104
except Exception as err:
103105
msg = 'Test connecting to DB failed'
104106
LOGGER.error(f'{msg}: {err}')

pygeoapi/provider/mvt_postgresql.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
TileSetMetadata, TileMatrixSetEnum, LinkType)
4141
from pygeoapi.provider.base import ProviderConnectionError
4242
from pygeoapi.provider.base_mvt import BaseMVTProvider
43-
from pygeoapi.provider.postgresql import PostgreSQLProvider
43+
from pygeoapi.provider.sql import PostgreSQLProvider
4444
from pygeoapi.provider.tile import ProviderTileNotFoundError
4545
from pygeoapi.util import url_join
4646

0 commit comments

Comments
 (0)