Skip to content

Commit

Permalink
add crud registry example implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
matthesrieke committed Aug 20, 2024
1 parent 3dbe214 commit 39bf85d
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 8 deletions.
41 changes: 41 additions & 0 deletions pygeoapi/flask_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"""Flask module providing the route paths to the api"""

import os
import json
from typing import Union

import click
Expand Down Expand Up @@ -609,6 +610,46 @@ def admin_config_resource(resource_id):
admin_ = Admin(CONFIG, OPENAPI)
APP.register_blueprint(ADMIN_BLUEPRINT)

REGISTRY_BLUEPRINT = Blueprint('_registry', __name__, static_folder=STATIC_FOLDER)

@REGISTRY_BLUEPRINT.route('/_registry/resources', methods=['GET', 'POST'])
def registry_resources():
"""
Registry endpoint
:returns: HTTP response
"""

if request.method == 'GET':
return get_response(([], 200, api_.get_registry().get_all_resources()))

elif request.method == 'POST':
data = json.loads(request.get_data(as_text=True))
print(data)
api_.get_registry().set_resource_config('test', data['test'])
return get_response(([], 200, api_.get_registry().get_resource_config('test')))


@REGISTRY_BLUEPRINT.route('/_registry/resources/<resource_id>', methods=['GET', 'PATCH', 'DELETE'])
def registry_resource():
"""
Registry endpoint
:returns: HTTP response
"""

if request.method == 'DELETE':
api_.get_registry().delete_resource_config()
return get_response(([], 200, {'deleted': True}))

pass




if (CONFIG['components'] and
'resource_registry' in CONFIG['components']):
APP.register_blueprint(REGISTRY_BLUEPRINT)

@click.command()
@click.pass_context
Expand Down
2 changes: 1 addition & 1 deletion pygeoapi/linked_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ def geojson2jsonld(cls, data: dict, dataset: str,
"""

LOGGER.debug('Fetching context and template from resource configuration')
jsonld = cls.config['resources'][dataset].get('linked-data', {})
jsonld = cls.get_registry().get_all_resources()[dataset].get('linked-data', {})
ds_url = f"{cls.get_collections_url()}/{dataset}"

context = jsonld.get('context', []).copy()
Expand Down
3 changes: 2 additions & 1 deletion pygeoapi/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@
'PostgreSQL': 'pygeoapi.process.manager.postgresql.PostgreSQLManager'
},
'resource_registry': {
'ConfigResourceRegistry': 'pygeoapi.registry.config_resource_registry.ConfigResourceRegistry'
'ConfigResourceRegistry': 'pygeoapi.registry.config_resource_registry.ConfigResourceRegistry',
'CrudConfigResourceRegistry': 'pygeoapi.registry.crud_config_resource_registry.CrudConfigResourceRegistry'
}
}

Expand Down
13 changes: 7 additions & 6 deletions pygeoapi/registry/config_resource_registry.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from pygeoapi.registry.resource_registry import ResourceRegistry
from pygeoapi.util import (filter_dict_by_key_value, get_provider_by_type)

"""
This registry implementation is a functional replacement of a config based
pygeoapi instance. Resources cannot be changed and are loaded at service start.
"""
class ConfigResourceRegistry(ResourceRegistry):

def __init__(self, plugin_def: dict):
super(ConfigResourceRegistry, self).__init__(plugin_def)
self.resources = plugin_def['resources']
self.resources_change_listeners = plugin_def['resources_change_listeners']

def get_all_resources(self) -> dict:
return self.resources
Expand All @@ -21,10 +23,10 @@ def get_resource_provider_of_type(self, resource_name: str,

def set_resource_config(self, resource_name: str,
configuration: dict) -> None:
self.call_change_listeners(self.resources)
pass

def delete_resource_config(self, resource_name: str) -> None:
self.call_change_listeners(self.resources)
pass

def get_resource_config(self, resource_name: str) -> dict:
if resource_name in self.resources:
Expand All @@ -33,5 +35,4 @@ def get_resource_config(self, resource_name: str) -> dict:
return None

def call_change_listeners(self, new_resources):
for cl in self.resources_change_listeners:
cl.on_resources_changed(new_resources)
pass
85 changes: 85 additions & 0 deletions pygeoapi/registry/crud_config_resource_registry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import sqlite3
import logging
import json

from pygeoapi.registry.resource_registry import ResourceRegistry
from pygeoapi.util import (filter_dict_by_key_value, get_provider_by_type)
"""
This registry implementation allows creation, update and removal of resources
"""

LOGGER = logging.getLogger(__name__)

class CrudConfigResourceRegistry(ResourceRegistry):

db_name = 'resources'

def __init__(self, plugin_def: dict):
super(CrudConfigResourceRegistry, self).__init__(plugin_def)
resources = plugin_def['resources']

self.resources_change_listeners = plugin_def['resources_change_listeners']

try:
# set up the database as a shared storage across workers
self.db_connection = sqlite3.connect("/tmp/pygeoapi_resources2.db")
cur = self.db_connection.cursor()
cur.execute(f'DROP TABLE IF EXISTS {CrudConfigResourceRegistry.db_name};')
cur.execute(f'CREATE TABLE IF NOT EXISTS {CrudConfigResourceRegistry.db_name}(name text PRIMARY KEY, configuration text);')

for k, v in resources.items():
cur.execute(f'INSERT INTO {CrudConfigResourceRegistry.db_name} VALUES(?, ?)', (k, json.dumps(v)))

LOGGER.info(f"Loaded {len(resources.items())} resources into SQLite")
cur.close()
self.db_connection.commit()

except Exception as e:
LOGGER.info('database locked: ' + str(e))


def get_all_resources(self) -> dict:
cur = self.db_connection.cursor()
cur.execute(f'SELECT * from {CrudConfigResourceRegistry.db_name};')
rows = cur.fetchall()
result = {}
for r in rows:
result[r[0]] = json.loads(r[1])
cur.close()

LOGGER.info(f"get all resources: {result}")

return result

def get_resources_of_type(self, target_type: str) -> dict:
return filter_dict_by_key_value(self.get_all_resources(), 'type', target_type)

def get_resource_provider_of_type(self, resource_name: str,
provider_type: str) -> dict:
return get_provider_by_type(self.get_all_resources()[resource_name]['providers'],
provider_type)

def set_resource_config(self, resource_name: str,
configuration: dict) -> None:
cur = self.db_connection.cursor()
cur.execute(f'INSERT INTO {CrudConfigResourceRegistry.db_name} VALUES(?, ?)', (resource_name, json.dumps(configuration)))
cur.close()
self.db_connection.commit()
self.call_change_listeners(self.get_all_resources())

def delete_resource_config(self, resource_name: str) -> None:
if resource_name in self.resources:
del self.resources[resource_name]

self.call_change_listeners(self.resources)

def get_resource_config(self, resource_name: str) -> dict:
res = self.get_all_resources()
if resource_name in res:
return res[resource_name]
else:
return None

def call_change_listeners(self, new_resources):
for cl in self.resources_change_listeners:
cl.on_resources_changed(new_resources)

0 comments on commit 39bf85d

Please sign in to comment.