Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Oracle Provider #1329

Merged
merged 40 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
05da4e5
Added Oracle Provider
May 10, 2023
ae58ab9
Changed author
May 16, 2023
04f23b2
Modified formatting with Black
May 16, 2023
76577e5
Merge branch 'geopython:master' into master
xkosubek May 26, 2023
f8fef75
Merge branch 'geopython:master' into master
xkosubek May 30, 2023
b20a774
Adapt Python Flake8 style
May 30, 2023
c7d5193
Merge branch 'master' of https://github.com/xkosubek/pygeoapi
May 30, 2023
a221fcd
Adapted line length
May 30, 2023
889b35d
Flake8
May 30, 2023
e2bfd4a
Line length <= 79
May 30, 2023
d5e68b2
Merge branch 'geopython:master' into master
xkosubek Jun 12, 2023
f796c84
Added Oracle provider into CI/CD
Jun 12, 2023
469f4d8
Changed code style to flake8
Jun 12, 2023
c26d5b8
style: tabs to spaces
Jun 12, 2023
b217532
style: line length
Jun 12, 2023
32d5403
style: trailing whitespaces
Jun 12, 2023
3e8d6c5
Changed dictionary concat to old style
Jun 12, 2023
fe12204
Fixed skip geometry error.
Jun 20, 2023
5793c7c
Added first set of unit tests
Jun 20, 2023
733cf90
Deleted whitespaces
Jun 20, 2023
706ad8d
Merge branch 'geopython:master' into master
xkosubek Jun 21, 2023
ff3421b
Added Oracle provider documentation
Jun 21, 2023
6482c57
First version Part 4 (CRUD)
Jun 21, 2023
b7f1b20
First version OGC API Feature Part 4 (CRUD)
Jun 21, 2023
95dd9de
Changed style for flake8
Jun 21, 2023
8c93808
Style: trailing whitespaces
Jun 21, 2023
6aef948
style: line too long
Jun 21, 2023
ea30a20
style: line too long
Jun 21, 2023
f117fd7
CRUD: Added update
Jun 21, 2023
bc6f060
flake nervt
Jun 21, 2023
8b3ef13
CRUD: update + delete
Jun 22, 2023
6a28ed0
Added tests + fixed errors
Jun 23, 2023
efd1960
Updated docs
Jun 23, 2023
4135cf6
Merge pull request #1 from xkosubek/feature/ogc-api-part4-crud
xkosubek Jun 23, 2023
074bd48
Merge branch 'geopython:master' into master
xkosubek Jun 23, 2023
3a04b23
Added test_get.. + Error fixing
Jun 23, 2023
fe29eb3
Worked reviews in
Jul 7, 2023
242f1a8
Merge branch 'geopython:master' into master
xkosubek Jul 7, 2023
215a386
Merge branch 'geopython:master' into master
xkosubek Sep 27, 2023
4a517b2
Added pull request comments
Sep 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,27 @@ jobs:
- python-version: 3.7
env:
PYGEOAPI_CONFIG: "$(pwd)/pygeoapi-config.yml"


services:
# Oracle service (label used to access the service container)
oracle:
# Docker Hub image (feel free to change the tag "latest" to any other available one)
image: gvenzl/oracle-xe:latest
# Provide passwords and other environment variables to container
env:
ORACLE_RANDOM_PASSWORD: true
APP_USER: geo_test
APP_USER_PASSWORD: geo_test
# Forward Oracle port
ports:
- 1521:1521
# Provide healthcheck script options for startup
options: >-
--health-cmd healthcheck.sh
--health-interval 10s
--health-timeout 5s
--health-retries 10

steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
Expand Down Expand Up @@ -105,6 +125,7 @@ jobs:
python3 tests/load_mongo_data.py tests/data/ne_110m_populated_places_simple.geojson
gunzip < tests/data/hotosm_bdi_waterways.sql.gz | psql postgresql://postgres:${{ secrets.DatabasePassword || 'postgres' }}@localhost:5432/test
psql postgresql://postgres:${{ secrets.DatabasePassword || 'postgres' }}@localhost:5432/test -f tests/data/dummy_data.sql
python3 tests/load_oracle_data.py
- name: run unit tests ⚙️
env:
POSTGRESQL_PASSWORD: ${{ secrets.DatabasePassword || 'postgres' }}
Expand All @@ -126,6 +147,7 @@ jobs:
pytest tests/test_ogr_sqlite_provider.py
pytest tests/test_ogr_wfs_provider.py
pytest tests/test_openapi.py
pytest tests/test_oracle_provider.py
pytest tests/test_postgresql_provider.py
pytest tests/test_rasterio_provider.py
pytest tests/test_sensorthings_provider.py
Expand Down
123 changes: 123 additions & 0 deletions docs/source/data-publishing/ogcapi-features.rst
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,129 @@ MongoDB
data: mongodb://localhost:27017/testdb
collection: testplaces

.. _Oracle:

Oracle
^^^^^^

.. note::
Requires Python package oracledb

.. code-block:: yaml

providers:
- type: feature
name: OracleDB
data:
host: 127.0.0.1
port: 1521 # defaults to 1521 if not provided
service_name: XEPDB1
# sid: XEPDB1
user: geo_test
password: geo_test
# external_auth: wallet
# tns_name: XEPDB1
# tns_admin /opt/oracle/client/network/admin
# init_oracle_client: True

id_field: id
table: lakes
geom_field: geometry
title_field: name
# sql_manipulator: tests.test_oracle_provider.SqlManipulator
# sql_manipulator_options:
# foo: bar
# mandatory_properties:
# - bbox
# source_crs: 31287 # defaults to 4326 if not provided
# target_crs: 31287 # defaults to 4326 if not provided

The provider supports connection over host and port with SID or SERVICE_NAME. For TNS naming, the system
environment variable TNS_ADMIN or the configuration parameter tns_admin must be set.

The providers supports external authentication. At the moment only wallet authentication is implemented.

Sometimes it is necessary to use the Oracle client for the connection. In this case init_oracle_client must be set to True.

The provider supports a SQL-Manipulator-Plugin class. With this, the SQL statement could be manipulated. This is
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this level of information (code blocks, etc.) can go in pygeoapi/provider/oracle.py and specify in the doc to consult the plugin itself? We should keep these sections of the docs more user focused.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about to link here to the test class? There is the example class, too.
Something like:

Sometimes it is necessary to use the Oracle client for the connection. In this case init_oracle_client must be set to True.

The provider supports a SQL-Manipulator-Plugin class. With this, the SQL statement could be manipulated. This is
useful e.g. for authorization at row level or manipulation of the explain plan with hints.
An example an more informations about that feature you can find in the test class in tests/test_oracle_provider.py.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

useful e.g. for authorization at row level or manipulation of the explain plan with hints. For this, the SQL
statement has three different placeholders which could be replaced: #HINTS#, #WHERE# and #JOIN#.

.. code-block:: sql

SELECT #HINTS# t1.id, ...
FROM table t1 #JOIN#
#WHERE#
ORDER BY t1.id ASC
OFFSET :offset ROWS FETCH NEXT :limit ROWS ONLY

Example SQL Manipulator
"""""""""""""""""""""""
.. code-block:: python

class SqlManipulator:
def process_query(
self,
db,
sql_query,
bind_variables,
sql_manipulator_options,
bbox,
source_crs,
properties,
):
sql = "ID = 10 AND :foo != :bar"

if sql_query.find(" WHERE ") == -1:
sql_query = sql_query.replace("#WHERE#", f" WHERE {sql}")
else:
sql_query = sql_query.replace("#WHERE#", f" AND {sql}")

bind_variables = {
**bind_variables,
"foo": "foo",
"bar": sql_manipulator_options.get("foo"),
}

return sql_query, bind_variables

def process_create(
self,
db,
sql_query,
bind_variables,
sql_manipulator_options,
request_data,
):
bind_variables["name"] = "overwritten"

return sql_query, bind_variables

def process_update(
self,
db,
sql_query,
bind_variables,
sql_manipulator_options,
identifier,
request_data,
):
bind_variables["area"] = 42
bind_variables["volume"] = 42

return sql_query, bind_variables

def process_delete(
self,
db,
sql_query,
bind_variables,
sql_manipulator_options,
identifier,
):
sql_query = f"{sql_query} AND 'auth' = 'you arent allowed'"

return sql_query, bind_variables

.. _PostgreSQL:

Expand Down
179 changes: 179 additions & 0 deletions oracle-config.yml
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this file (given we have an example in tests.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the full configuration files are beneficial to keep, alternatively consider creating an oracle docker example.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, there is no benefit. Everything is in the documentation, too. I only forgot to delete this file...

Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
# =================================================================
#
# Authors: Andreas Kosubek <[email protected]>
#
# Copyright (c) 2023 Andreas Kosubek
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# =================================================================

server:
bind:
host: 0.0.0.0
port: 5000
url: http://localhost:5000
mimetype: application/json; charset=UTF-8
encoding: utf-8
gzip: false
languages:
# First language is the default language
- en-US
- fr-CA
# cors: true
pretty_print: true
limit: 10
# templates:
# path: /path/to/Jinja2/templates
# static: /path/to/static/folder # css/js/img
map:
url: https://tile.openstreetmap.org/{z}/{x}/{y}.png
attribution: '&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a>'
# manager:
# name: TinyDB
# connection: /tmp/pygeoapi-process-manager.db
# output_dir: /tmp/
# ogc_schemas_location: /opt/schemas.opengis.net

logging:
level: DEBUG
#logfile: /tmp/pygeoapi.log

metadata:
identification:
title:
en: pygeoapi default instance
fr: instance par défaut de pygeoapi
description:
en: pygeoapi provides an API to geospatial data
fr: pygeoapi fournit une API aux données géospatiales
keywords:
en:
- geospatial
- data
- api
fr:
- géospatiale
- données
- api
keywords_type: theme
terms_of_service: https://creativecommons.org/licenses/by/4.0/
url: https://example.org
license:
name: CC-BY 4.0 license
url: https://creativecommons.org/licenses/by/4.0/
provider:
name: Organization Name
url: https://pygeoapi.io
contact:
name: Lastname, Firstname
position: Position Title
address: Mailing Address
city: City
stateorprovince: Administrative Area
postalcode: Zip or Postal Code
country: Country
phone: +xx-xxx-xxx-xxxx
fax: +xx-xxx-xxx-xxxx
email: [email protected]
url: Contact URL
hours: Mo-Fr 08:00-17:00
instructions: During hours of service. Off on weekends.
role: pointOfContact

resources:
lakes:
type: collection
title:
en: Large Lakes
fr: Grands Lacs
description:
en: lakes of the world, public domain
fr: lacs du monde, domaine public
keywords:
en:
- lakes
- water bodies
fr:
- lacs
- plans d'eau
links:
- type: text/html
rel: canonical
title: information
href: http://www.naturalearthdata.com/
hreflang: en-US
extents:
spatial:
bbox: [-180,-90,180,90]
crs: http://www.opengis.net/def/crs/OGC/1.3/CRS84
temporal:
begin: 2011-11-11T11:11:11Z
end: null # or empty (either means open ended)
providers:
- type: feature
name: GeoJSON
data: tests/data/ne_110m_lakes.geojson
id_field: id
title_field: name

orcl-lakes:
type: collection
title:
en: Large Lakes (Oracle)
fr: Grands Lacs (Oracle)
description:
en: lakes of the world, public domain
fr: lacs du monde, domaine public
keywords:
en:
- lakes
- water bodies
fr:
- lacs
- plans d'eau
links:
- type: text/html
rel: canonical
title: information
href: http://www.naturalearthdata.com/
hreflang: en-US
extents:
spatial:
bbox: [-180,-90,180,90]
crs: http://www.opengis.net/def/crs/OGC/1.3/CRS84
temporal:
begin: 2011-11-11T11:11:11Z
end: null # or empty (either means open ended)
providers:
- type: feature
name: OracleDB
data:
host: 127.0.0.1
port: 1521
service_name: XEPDB1
user: geo_test
password: geo_test
id_field: id
table: lakes
geom_field: geometry
title_field: name
Loading
Loading