diff --git a/.jupyter/deposit.ipynb b/.jupyter/deposit.ipynb index e70bd060e49ed9abb4eec88a0c3fb543d439cf4c..8d976d0964e1334c736b44f244f6aa197c3452ff 100644 --- a/.jupyter/deposit.ipynb +++ b/.jupyter/deposit.ipynb @@ -324,7 +324,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [] } @@ -350,4 +354,4 @@ }, "nbformat": 4, "nbformat_minor": 1 -} +} \ No newline at end of file diff --git a/.jupyter/feature_extract.ipynb b/.jupyter/feature_extract.ipynb index a4bd8ad724ba05135161e66790a21efe977db7a1..1c848c824e0f4cfc2d8dc1b0fe715a8f2e79b0a9 100644 --- a/.jupyter/feature_extract.ipynb +++ b/.jupyter/feature_extract.ipynb @@ -893,7 +893,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [] } diff --git a/.jupyter/test.ipynb b/.jupyter/test.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..70b2c3573649bf6e57347b8a3834c3a0fb5952f4 --- /dev/null +++ b/.jupyter/test.ipynb @@ -0,0 +1,1016 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "# Test Jupyter Notebook" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import time\n", + "import os\n", + "import shutil\n", + "import uuid\n", + "\n", + "from api_authentication.api.authentication_endpoint_api import AuthenticationEndpointApi\n", + "from api_authentication.api.user_endpoint_api import UserEndpointApi\n", + "from api_container.api.container_endpoint_api import ContainerEndpointApi\n", + "from api_database.api.container_database_endpoint_api import ContainerDatabaseEndpointApi\n", + "from api_table.api.table_endpoint_api import TableEndpointApi\n", + "from api_query.api.table_data_endpoint_api import TableDataEndpointApi\n", + "from api_query.api.query_endpoint_api import QueryEndpointApi\n", + "from api_identifier.api.identifier_endpoint_api import IdentifierEndpointApi\n", + "from api_identifier.api.persistence_endpoint_api import PersistenceEndpointApi\n", + "\n", + "authentication = AuthenticationEndpointApi()\n", + "user = UserEndpointApi()\n", + "container = ContainerEndpointApi()\n", + "database = ContainerDatabaseEndpointApi()\n", + "table = TableEndpointApi()\n", + "query = QueryEndpointApi()\n", + "data = TableDataEndpointApi()\n", + "identifier = IdentifierEndpointApi()\n", + "persistence = PersistenceEndpointApi()\n", + "\n", + "username = \"user\"\n", + "password = \"user\"\n", + "email = \"someone@example.com\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "Create user" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'affiliation': None,\n", + " 'authorities': [{'authority': 'ROLE_RESEARCHER'}],\n", + " 'containers': None,\n", + " 'databases': None,\n", + " 'email': 'someone@example.com',\n", + " 'email_verified': False,\n", + " 'firstname': None,\n", + " 'id': 2,\n", + " 'identifiers': None,\n", + " 'lastname': None,\n", + " 'orcid': None,\n", + " 'titles_after': None,\n", + " 'titles_before': None,\n", + " 'username': 'user'}\n" + ] + } + ], + "source": [ + "response = user.register({\n", + " \"username\": username,\n", + " \"password\": password,\n", + " \"email\": email\n", + "})\n", + "print(response)" + ] + }, + { + "cell_type": "markdown", + "source": [ + "Create token" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 70, + "outputs": [], + "source": [ + "response = authentication.authenticate_user1({\n", + " \"username\": username,\n", + " \"password\": password\n", + "})\n", + "user_id = response.id\n", + "token = response.token\n", + "container.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}\n", + "database.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}\n", + "table.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}\n", + "data.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}\n", + "query.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}\n", + "identifier.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}\n", + "user.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}\n", + "persistence.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Create container" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 71, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'created': datetime.datetime(2022, 7, 23, 10, 36, 8, 105000, tzinfo=tzutc()),\n", + " 'creator': {'affiliation': None,\n", + " 'authorities': None,\n", + " 'email': 'someone@example.com',\n", + " 'email_verified': False,\n", + " 'firstname': None,\n", + " 'id': 2,\n", + " 'lastname': None,\n", + " 'orcid': None,\n", + " 'titles_after': None,\n", + " 'titles_before': None,\n", + " 'username': 'user'},\n", + " 'hash': '0bb51761983c2adadc995d95a8ae2a1ae8ba5e9c18c05ad2631189f40eef194b',\n", + " 'id': 1,\n", + " 'internal_name': 'fda-userdb-airquality-429d627e-0a73-11ed-95b6-4f6e5b6c5022',\n", + " 'is_public': None,\n", + " 'name': 'Airquality 429d627e-0a73-11ed-95b6-4f6e5b6c5022'}\n" + ] + } + ], + "source": [ + "response = container.create1({\n", + " \"name\": \"Airquality \" + str(uuid.uuid1()),\n", + " \"repository\": \"mariadb\",\n", + " \"tag\": \"10.5\"\n", + "})\n", + "container_id = response.id\n", + "print(response)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Start container" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 72, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'created': datetime.datetime(2022, 7, 23, 10, 36, 8, 105000, tzinfo=tzutc()),\n", + " 'creator': {'affiliation': None,\n", + " 'authorities': None,\n", + " 'email': 'someone@example.com',\n", + " 'email_verified': False,\n", + " 'firstname': None,\n", + " 'id': 2,\n", + " 'lastname': None,\n", + " 'orcid': None,\n", + " 'titles_after': None,\n", + " 'titles_before': None,\n", + " 'username': 'user'},\n", + " 'hash': '0bb51761983c2adadc995d95a8ae2a1ae8ba5e9c18c05ad2631189f40eef194b',\n", + " 'id': 1,\n", + " 'internal_name': 'fda-userdb-airquality-429d627e-0a73-11ed-95b6-4f6e5b6c5022',\n", + " 'is_public': None,\n", + " 'name': 'Airquality 429d627e-0a73-11ed-95b6-4f6e5b6c5022'}\n" + ] + } + ], + "source": [ + "response = container.modify({\n", + " \"action\": \"start\"\n", + "}, container_id)\n", + "print(response)\n", + "time.sleep(5)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Create database" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 73, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'container': {'created': datetime.datetime(2022, 7, 23, 10, 36, 8, 105000, tzinfo=tzutc()),\n", + " 'creator': {'affiliation': None,\n", + " 'authorities': None,\n", + " 'email': 'someone@example.com',\n", + " 'email_verified': False,\n", + " 'firstname': None,\n", + " 'id': 2,\n", + " 'lastname': None,\n", + " 'orcid': None,\n", + " 'titles_after': None,\n", + " 'titles_before': None,\n", + " 'username': 'user'},\n", + " 'hash': '0bb51761983c2adadc995d95a8ae2a1ae8ba5e9c18c05ad2631189f40eef194b',\n", + " 'id': 1,\n", + " 'internal_name': 'fda-userdb-airquality-429d627e-0a73-11ed-95b6-4f6e5b6c5022',\n", + " 'is_public': None,\n", + " 'name': 'Airquality 429d627e-0a73-11ed-95b6-4f6e5b6c5022'},\n", + " 'created': datetime.datetime(2022, 7, 23, 10, 36, 14, 568000, tzinfo=tzutc()),\n", + " 'creator': {'affiliation': None,\n", + " 'authorities': None,\n", + " 'email': 'someone@example.com',\n", + " 'email_verified': False,\n", + " 'firstname': None,\n", + " 'id': 2,\n", + " 'lastname': None,\n", + " 'orcid': None,\n", + " 'titles_after': None,\n", + " 'titles_before': None,\n", + " 'username': 'user'},\n", + " 'description': 'Hourly measurements in Zürich, Switzerland',\n", + " 'engine': 'mariadb:10.5',\n", + " 'id': 1,\n", + " 'is_public': True,\n", + " 'name': 'Airquality 466a3472-0a73-11ed-95b6-4f6e5b6c5022'}\n" + ] + } + ], + "source": [ + "response = database.create({\n", + " \"name\": \"Airquality \" + str(uuid.uuid1()),\n", + " \"description\": \"Hourly measurements in Zürich, Switzerland\",\n", + " \"is_public\": True\n", + "}, container_id)\n", + "database_id = response.id\n", + "print(response)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Inspect database" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 74, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'contact': None,\n", + " 'container': {'created': datetime.datetime(2022, 7, 23, 10, 36, 8, 105000, tzinfo=tzutc()),\n", + " 'databases': None,\n", + " 'hash': '0bb51761983c2adadc995d95a8ae2a1ae8ba5e9c18c05ad2631189f40eef194b',\n", + " 'id': 1,\n", + " 'image': {'id': 1, 'repository': 'mariadb', 'tag': '10.5'},\n", + " 'internal_name': 'fda-userdb-airquality-429d627e-0a73-11ed-95b6-4f6e5b6c5022',\n", + " 'ip_address': None,\n", + " 'is_public': None,\n", + " 'name': 'Airquality 429d627e-0a73-11ed-95b6-4f6e5b6c5022',\n", + " 'port': 35971,\n", + " 'state': None},\n", + " 'created': datetime.datetime(2022, 7, 23, 10, 36, 14, 568000, tzinfo=tzutc()),\n", + " 'creator': {'affiliation': None,\n", + " 'authorities': None,\n", + " 'containers': None,\n", + " 'databases': None,\n", + " 'email': 'someone@example.com',\n", + " 'email_verified': False,\n", + " 'firstname': None,\n", + " 'id': 2,\n", + " 'identifiers': None,\n", + " 'lastname': None,\n", + " 'orcid': None,\n", + " 'titles_after': None,\n", + " 'titles_before': None,\n", + " 'username': 'user'},\n", + " 'deleted': None,\n", + " 'description': 'Hourly measurements in Zürich, Switzerland',\n", + " 'exchange': 'airquality_466a3472-0a73-11ed-95b6-4f6e5b6c5022',\n", + " 'id': 1,\n", + " 'image': {'compiled': None,\n", + " 'date_formats': [{'created_at': datetime.datetime(2022, 7, 23, 10, 35, 9, 33000, tzinfo=tzutc()),\n", + " 'database_format': '%Y-%c-%d',\n", + " 'example': '2022-01-30',\n", + " 'has_time': False,\n", + " 'id': 1,\n", + " 'unix_format': 'yyyy-MM-dd'},\n", + " {'created_at': datetime.datetime(2022, 7, 23, 10, 35, 9, 43000, tzinfo=tzutc()),\n", + " 'database_format': '%d.%c.%Y',\n", + " 'example': '30.01.2022',\n", + " 'has_time': False,\n", + " 'id': 2,\n", + " 'unix_format': 'yyyy-MM-dd'},\n", + " {'created_at': datetime.datetime(2022, 7, 23, 10, 35, 9, 46000, tzinfo=tzutc()),\n", + " 'database_format': '%d.%c.%y',\n", + " 'example': '30.01.22',\n", + " 'has_time': False,\n", + " 'id': 3,\n", + " 'unix_format': 'yyyy-MM-dd'},\n", + " {'created_at': datetime.datetime(2022, 7, 23, 10, 35, 9, 50000, tzinfo=tzutc()),\n", + " 'database_format': '%c/%d/%Y',\n", + " 'example': '01/30/2022',\n", + " 'has_time': False,\n", + " 'id': 4,\n", + " 'unix_format': 'yyyy-MM-dd'},\n", + " {'created_at': datetime.datetime(2022, 7, 23, 10, 35, 9, 55000, tzinfo=tzutc()),\n", + " 'database_format': '%c/%d/%y',\n", + " 'example': '01/30/22',\n", + " 'has_time': False,\n", + " 'id': 5,\n", + " 'unix_format': 'yyyy-MM-dd'},\n", + " {'created_at': datetime.datetime(2022, 7, 23, 10, 35, 9, 59000, tzinfo=tzutc()),\n", + " 'database_format': '%Y-%c-%d %H:%i:%S.%f',\n", + " 'example': '2022-01-30 13:44:25.0',\n", + " 'has_time': True,\n", + " 'id': 6,\n", + " 'unix_format': 'yyyy-MM-dd HH:mm:ss.SSSSSS'},\n", + " {'created_at': datetime.datetime(2022, 7, 23, 10, 35, 9, 63000, tzinfo=tzutc()),\n", + " 'database_format': '%Y-%c-%d %H:%i:%S',\n", + " 'example': '2022-01-30 13:44:25',\n", + " 'has_time': True,\n", + " 'id': 7,\n", + " 'unix_format': 'yyyy-MM-dd HH:mm:ss'},\n", + " {'created_at': datetime.datetime(2022, 7, 23, 10, 35, 9, 67000, tzinfo=tzutc()),\n", + " 'database_format': '%d.%c.%Y %H:%i:%S',\n", + " 'example': '30.01.2022 13:44:25',\n", + " 'has_time': True,\n", + " 'id': 8,\n", + " 'unix_format': 'dd.MM.yyyy HH:mm:ss'}],\n", + " 'default_port': 3306,\n", + " 'dialect': 'org.hibernate.dialect.MariaDBDialect',\n", + " 'driver_class': 'org.mariadb.jdbc.Driver',\n", + " 'environment': [{'iid': 1,\n", + " 'key': 'ROOT',\n", + " 'type': 'PRIVILEGED_USERNAME',\n", + " 'value': 'root'},\n", + " {'iid': 1,\n", + " 'key': 'MARIADB_ROOT_PASSWORD',\n", + " 'type': 'PRIVILEGED_PASSWORD',\n", + " 'value': 'mariadb'},\n", + " {'iid': 1,\n", + " 'key': 'MARIADB_USER',\n", + " 'type': 'USERNAME',\n", + " 'value': 'mariadb'},\n", + " {'iid': 1,\n", + " 'key': 'MARIADB_PASSWORD',\n", + " 'type': 'PASSWORD',\n", + " 'value': 'mariadb'}],\n", + " 'hash': None,\n", + " 'id': 1,\n", + " 'jdbc_method': 'mariadb',\n", + " 'repository': 'mariadb',\n", + " 'size': None,\n", + " 'tag': '10.5'},\n", + " 'internal_name': 'airquality_466a3472-0a73-11ed-95b6-4f6e5b6c5022',\n", + " 'is_public': True,\n", + " 'language': None,\n", + " 'license': None,\n", + " 'name': 'Airquality 466a3472-0a73-11ed-95b6-4f6e5b6c5022',\n", + " 'publication': None,\n", + " 'publisher': None,\n", + " 'subjects': [],\n", + " 'tables': []}\n" + ] + } + ], + "source": [ + "response = database.find_by_id(container_id, database_id)\n", + "database_exchange = response.exchange\n", + "print(response)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Add metadata to database" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 75, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'container': {'created': datetime.datetime(2022, 7, 23, 10, 36, 8, 105000, tzinfo=tzutc()),\n", + " 'creator': {'affiliation': None,\n", + " 'authorities': None,\n", + " 'email': 'someone@example.com',\n", + " 'email_verified': False,\n", + " 'firstname': None,\n", + " 'id': 2,\n", + " 'lastname': None,\n", + " 'orcid': None,\n", + " 'titles_after': None,\n", + " 'titles_before': None,\n", + " 'username': 'user'},\n", + " 'hash': '0bb51761983c2adadc995d95a8ae2a1ae8ba5e9c18c05ad2631189f40eef194b',\n", + " 'id': 1,\n", + " 'internal_name': 'fda-userdb-airquality-429d627e-0a73-11ed-95b6-4f6e5b6c5022',\n", + " 'is_public': None,\n", + " 'name': 'Airquality 429d627e-0a73-11ed-95b6-4f6e5b6c5022'},\n", + " 'created': datetime.datetime(2022, 7, 23, 10, 36, 14, 568000, tzinfo=tzutc()),\n", + " 'creator': {'affiliation': None,\n", + " 'authorities': None,\n", + " 'email': 'someone@example.com',\n", + " 'email_verified': False,\n", + " 'firstname': None,\n", + " 'id': 2,\n", + " 'lastname': None,\n", + " 'orcid': None,\n", + " 'titles_after': None,\n", + " 'titles_before': None,\n", + " 'username': 'user'},\n", + " 'description': 'This dataset includes daily values from 1983 to the current '\n", + " 'day, divided into annual files. This includes the maximum '\n", + " 'hourly average and the number of times the hourly average '\n", + " 'limit value for ozone was exceeded and the daily averages for '\n", + " 'sulfur dioxide (SO2), carbon monoxide (CO), nitrogen oxide '\n", + " '(NOx), nitrogen monoxide (NO), nitrogen dioxide (NO2), '\n", + " 'particulate matter (PM10 and PM2.5). ) and particle number '\n", + " '(PN), provided that they are of sufficient quality. The '\n", + " 'values of the completed day for the current year are updated '\n", + " 'every 30 minutes after midnight (UTC+1).',\n", + " 'engine': 'mariadb:10.5',\n", + " 'id': 1,\n", + " 'is_public': True,\n", + " 'name': 'Airquality 466a3472-0a73-11ed-95b6-4f6e5b6c5022'}\n" + ] + } + ], + "source": [ + "response = database.update({\n", + " \"description\": \"This dataset includes daily values from 1983 to the current day, divided into annual files. This includes the maximum hourly average and the number of times the hourly average limit value for ozone was exceeded and the daily averages for sulfur dioxide (SO2), carbon monoxide (CO), nitrogen oxide (NOx), nitrogen monoxide (NO), nitrogen dioxide (NO2), particulate matter (PM10 and PM2.5). ) and particle number (PN), provided that they are of sufficient quality. The values of the completed day for the current year are updated every 30 minutes after midnight (UTC+1).\",\n", + " \"publisher\": \"Technical University of Vienna\",\n", + " \"license\": {\n", + " \"identifier\": \"CC0-1.0\",\n", + " \"uri\": \"https://creativecommons.org/publicdomain/zero/1.0/legalcode\"\n", + " },\n", + " \"language\": \"en\",\n", + " \"is_public\": True,\n", + " \"publication\": \"2022-07-19\"\n", + "}, container_id, database_id)\n", + "print(response)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Create table" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 76, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'creator': {'affiliation': None,\n", + " 'authorities': None,\n", + " 'email': 'someone@example.com',\n", + " 'email_verified': False,\n", + " 'firstname': None,\n", + " 'id': 2,\n", + " 'lastname': None,\n", + " 'orcid': None,\n", + " 'titles_after': None,\n", + " 'titles_before': None,\n", + " 'username': 'user'},\n", + " 'id': 1,\n", + " 'internal_name': 'airquality_466a3473-0a73-11ed-95b6-4f6e5b6c5022',\n", + " 'name': 'Airquality 466a3473-0a73-11ed-95b6-4f6e5b6c5022'}\n" + ] + } + ], + "source": [ + "response = table.create({\n", + " \"name\": \"Airquality \" + str(uuid.uuid1()),\n", + " \"description\": \"Airquality in Zürich, Switzerland\",\n", + " \"columns\": [{\n", + " \"name\": \"Date\",\n", + " \"type\": \"date\",\n", + " \"dfid\": 1,\n", + " \"unique\": False,\n", + " \"primary_key\": False,\n", + " \"null_allowed\": True,\n", + " }, {\n", + " \"name\": \"Location\",\n", + " \"type\": \"string\",\n", + " \"unique\": False,\n", + " \"primary_key\": False,\n", + " \"null_allowed\": True,\n", + " }, {\n", + " \"name\": \"Parameter\",\n", + " \"type\": \"string\",\n", + " \"unique\": False,\n", + " \"primary_key\": False,\n", + " \"null_allowed\": True,\n", + " }, {\n", + " \"name\": \"Interval\",\n", + " \"type\": \"string\",\n", + " \"unique\": False,\n", + " \"primary_key\": False,\n", + " \"null_allowed\": True,\n", + " }, {\n", + " \"name\": \"Unit\",\n", + " \"type\": \"string\",\n", + " \"unique\": False,\n", + " \"primary_key\": False,\n", + " \"null_allowed\": True,\n", + " }, {\n", + " \"name\": \"Value\",\n", + " \"type\": \"decimal\",\n", + " \"unique\": False,\n", + " \"primary_key\": False,\n", + " \"null_allowed\": True,\n", + " }, {\n", + " \"name\": \"Status\",\n", + " \"type\": \"string\",\n", + " \"unique\": False,\n", + " \"primary_key\": False,\n", + " \"null_allowed\": True,\n", + " }]\n", + "}, container_id, database_id)\n", + "table_id = response.id\n", + "print(response)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Inspect table" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 77, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'columns': [{'auto_generated': True,\n", + " 'check_expression': None,\n", + " 'column_concept': None,\n", + " 'column_type': 'number',\n", + " 'date_format': None,\n", + " 'decimal_digits_after': None,\n", + " 'decimal_digits_before': None,\n", + " 'enum_values': [],\n", + " 'foreign_key': None,\n", + " 'id': 1,\n", + " 'internal_name': 'id',\n", + " 'is_null_allowed': False,\n", + " 'is_primary_key': True,\n", + " 'name': 'id',\n", + " 'references': None,\n", + " 'unique': True},\n", + " {'auto_generated': False,\n", + " 'check_expression': None,\n", + " 'column_concept': None,\n", + " 'column_type': 'date',\n", + " 'date_format': {'created_at': datetime.datetime(2022, 7, 23, 10, 35, 9, 33000, tzinfo=tzutc()),\n", + " 'database_format': '%Y-%c-%d',\n", + " 'example': '2022-01-30',\n", + " 'has_time': False,\n", + " 'id': 1,\n", + " 'unix_format': 'yyyy-MM-dd'},\n", + " 'decimal_digits_after': None,\n", + " 'decimal_digits_before': None,\n", + " 'enum_values': [],\n", + " 'foreign_key': None,\n", + " 'id': 2,\n", + " 'internal_name': 'date',\n", + " 'is_null_allowed': True,\n", + " 'is_primary_key': False,\n", + " 'name': 'Date',\n", + " 'references': None,\n", + " 'unique': False},\n", + " {'auto_generated': False,\n", + " 'check_expression': None,\n", + " 'column_concept': None,\n", + " 'column_type': 'string',\n", + " 'date_format': None,\n", + " 'decimal_digits_after': None,\n", + " 'decimal_digits_before': None,\n", + " 'enum_values': [],\n", + " 'foreign_key': None,\n", + " 'id': 3,\n", + " 'internal_name': 'location',\n", + " 'is_null_allowed': True,\n", + " 'is_primary_key': False,\n", + " 'name': 'Location',\n", + " 'references': None,\n", + " 'unique': False},\n", + " {'auto_generated': False,\n", + " 'check_expression': None,\n", + " 'column_concept': None,\n", + " 'column_type': 'string',\n", + " 'date_format': None,\n", + " 'decimal_digits_after': None,\n", + " 'decimal_digits_before': None,\n", + " 'enum_values': [],\n", + " 'foreign_key': None,\n", + " 'id': 4,\n", + " 'internal_name': 'parameter',\n", + " 'is_null_allowed': True,\n", + " 'is_primary_key': False,\n", + " 'name': 'Parameter',\n", + " 'references': None,\n", + " 'unique': False},\n", + " {'auto_generated': False,\n", + " 'check_expression': None,\n", + " 'column_concept': None,\n", + " 'column_type': 'string',\n", + " 'date_format': None,\n", + " 'decimal_digits_after': None,\n", + " 'decimal_digits_before': None,\n", + " 'enum_values': [],\n", + " 'foreign_key': None,\n", + " 'id': 5,\n", + " 'internal_name': 'interval',\n", + " 'is_null_allowed': True,\n", + " 'is_primary_key': False,\n", + " 'name': 'Interval',\n", + " 'references': None,\n", + " 'unique': False},\n", + " {'auto_generated': False,\n", + " 'check_expression': None,\n", + " 'column_concept': None,\n", + " 'column_type': 'string',\n", + " 'date_format': None,\n", + " 'decimal_digits_after': None,\n", + " 'decimal_digits_before': None,\n", + " 'enum_values': [],\n", + " 'foreign_key': None,\n", + " 'id': 6,\n", + " 'internal_name': 'unit',\n", + " 'is_null_allowed': True,\n", + " 'is_primary_key': False,\n", + " 'name': 'Unit',\n", + " 'references': None,\n", + " 'unique': False},\n", + " {'auto_generated': False,\n", + " 'check_expression': None,\n", + " 'column_concept': None,\n", + " 'column_type': 'decimal',\n", + " 'date_format': None,\n", + " 'decimal_digits_after': None,\n", + " 'decimal_digits_before': None,\n", + " 'enum_values': [],\n", + " 'foreign_key': None,\n", + " 'id': 7,\n", + " 'internal_name': 'value',\n", + " 'is_null_allowed': True,\n", + " 'is_primary_key': False,\n", + " 'name': 'Value',\n", + " 'references': None,\n", + " 'unique': False},\n", + " {'auto_generated': False,\n", + " 'check_expression': None,\n", + " 'column_concept': None,\n", + " 'column_type': 'string',\n", + " 'date_format': None,\n", + " 'decimal_digits_after': None,\n", + " 'decimal_digits_before': None,\n", + " 'enum_values': [],\n", + " 'foreign_key': None,\n", + " 'id': 8,\n", + " 'internal_name': 'status',\n", + " 'is_null_allowed': True,\n", + " 'is_primary_key': False,\n", + " 'name': 'Status',\n", + " 'references': None,\n", + " 'unique': False}],\n", + " 'created': datetime.datetime(2022, 7, 23, 10, 36, 16, 462000, tzinfo=tzutc()),\n", + " 'description': 'Airquality in Zürich, Switzerland',\n", + " 'id': 1,\n", + " 'internal_name': 'airquality_466a3473-0a73-11ed-95b6-4f6e5b6c5022',\n", + " 'name': 'Airquality 466a3473-0a73-11ed-95b6-4f6e5b6c5022',\n", + " 'topic': 'airquality_466a3473-0a73-11ed-95b6-4f6e5b6c5022'}\n" + ] + } + ], + "source": [ + "response = table.find_by_id(container_id, database_id, table_id)\n", + "table_internal_name = response.internal_name\n", + "table_topic = response.topic\n", + "print(response)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Import .csv" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 78, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "210192\n" + ] + } + ], + "source": [ + "shutil.copyfile(os.getcwd() + \"/resources/ugz_ogd_air_h1_2021.csv\", \"/tmp/ugz_ogd_air_h1_2021.csv\")\n", + "response = data.import_csv({\n", + " \"location\": \"/tmp/ugz_ogd_air_h1_2021.csv\",\n", + " \"separator\": \",\",\n", + " \"quote\": \"\\\"\",\n", + " \"skip_lines\": 1\n", + "}, container_id, database_id, table_id)\n", + "print(response)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Create subset" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 84, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'id': 6,\n", + " 'result': [{'Date': '2021-01-01T00:00:00Z',\n", + " 'Interval': 'h1',\n", + " 'Location': 'Schimmelstrasse',\n", + " 'Parameter': 'NOx',\n", + " 'Status': 'tentative',\n", + " 'Unit': 'ppb',\n", + " 'Value': 41.66},\n", + " {'Date': '2021-01-01T00:00:00Z',\n", + " 'Interval': 'h1',\n", + " 'Location': 'Schimmelstrasse',\n", + " 'Parameter': 'NO',\n", + " 'Status': 'tentative',\n", + " 'Unit': 'µg/m3',\n", + " 'Value': 21.64},\n", + " {'Date': '2021-01-01T00:00:00Z',\n", + " 'Interval': 'h1',\n", + " 'Location': 'Schimmelstrasse',\n", + " 'Parameter': 'NO2',\n", + " 'Status': 'tentative',\n", + " 'Unit': 'µg/m3',\n", + " 'Value': 46.49}],\n", + " 'result_number': 52548}\n" + ] + } + ], + "source": [ + "response = query.execute({\n", + " \"statement\": \"select `date`, `location`, `parameter`, `interval`, `unit`, `value`, `status` from `\" + table_internal_name + \"` where `location` = 'Schimmelstrasse'\"\n", + "}, container_id, database_id, page=0, size=3)\n", + "query_id = response.id\n", + "print(response)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "Create invalid subset" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%% md\n" + } + } + }, + { + "cell_type": "code", + "execution_count": 85, + "outputs": [ + { + "ename": "ApiException", + "evalue": "(400)\nReason: Bad Request\nHTTP response headers: HTTPHeaderDict({'transfer-encoding': 'chunked', 'Vary': 'Origin, Access-Control-Request-Method, Access-Control-Request-Headers', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '1; mode=block', 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'X-Frame-Options': 'DENY', 'Content-Type': 'application/json', 'Date': 'Sat, 23 Jul 2022 10:53:23 GMT'})\nHTTP response body: b'{\"status\":\"BAD_REQUEST\",\"message\":\"Query not valid for this database\",\"code\":\"error.query.malformed\"}'\n", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mApiException\u001B[0m Traceback (most recent call last)", + "Input \u001B[0;32mIn [85]\u001B[0m, in \u001B[0;36m<cell line: 1>\u001B[0;34m()\u001B[0m\n\u001B[0;32m----> 1\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[43mquery\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mexecute\u001B[49m\u001B[43m(\u001B[49m\u001B[43m{\u001B[49m\n\u001B[1;32m 2\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mstatement\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m:\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mselect `date`, `location`, `parameter`, `interval`, `unit`, `value`, `status` from `\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;241;43m+\u001B[39;49m\u001B[43m \u001B[49m\u001B[43mtable_internal_name\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m+\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43m` where `foo` = \u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mbar\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\n\u001B[1;32m 3\u001B[0m \u001B[43m}\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mcontainer_id\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mdatabase_id\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mpage\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43msize\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m3\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[1;32m 4\u001B[0m \u001B[38;5;28mprint\u001B[39m(response)\n", + "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/api/query_endpoint_api.py:57\u001B[0m, in \u001B[0;36mQueryEndpointApi.execute\u001B[0;34m(self, body, id, database_id, **kwargs)\u001B[0m\n\u001B[1;32m 55\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mexecute_with_http_info(body, \u001B[38;5;28mid\u001B[39m, database_id, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs) \u001B[38;5;66;03m# noqa: E501\u001B[39;00m\n\u001B[1;32m 56\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m---> 57\u001B[0m (data) \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mexecute_with_http_info\u001B[49m\u001B[43m(\u001B[49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mid\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mdatabase_id\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkwargs\u001B[49m\u001B[43m)\u001B[49m \u001B[38;5;66;03m# noqa: E501\u001B[39;00m\n\u001B[1;32m 58\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m data\n", + "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/api/query_endpoint_api.py:140\u001B[0m, in \u001B[0;36mQueryEndpointApi.execute_with_http_info\u001B[0;34m(self, body, id, database_id, **kwargs)\u001B[0m\n\u001B[1;32m 137\u001B[0m \u001B[38;5;66;03m# Authentication setting\u001B[39;00m\n\u001B[1;32m 138\u001B[0m auth_settings \u001B[38;5;241m=\u001B[39m [\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mbearerAuth\u001B[39m\u001B[38;5;124m'\u001B[39m] \u001B[38;5;66;03m# noqa: E501\u001B[39;00m\n\u001B[0;32m--> 140\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mapi_client\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcall_api\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 141\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m/api/container/\u001B[39;49m\u001B[38;5;132;43;01m{id}\u001B[39;49;00m\u001B[38;5;124;43m/database/\u001B[39;49m\u001B[38;5;132;43;01m{databaseId}\u001B[39;49;00m\u001B[38;5;124;43m/query\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mPUT\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 142\u001B[0m \u001B[43m \u001B[49m\u001B[43mpath_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 143\u001B[0m \u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 144\u001B[0m \u001B[43m \u001B[49m\u001B[43mheader_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 145\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mbody_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 146\u001B[0m \u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mform_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 147\u001B[0m \u001B[43m \u001B[49m\u001B[43mfiles\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mlocal_var_files\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 148\u001B[0m \u001B[43m \u001B[49m\u001B[43mresponse_type\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mQueryResultDto\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;66;43;03m# noqa: E501\u001B[39;49;00m\n\u001B[1;32m 149\u001B[0m \u001B[43m \u001B[49m\u001B[43mauth_settings\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mauth_settings\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 150\u001B[0m \u001B[43m \u001B[49m\u001B[43masync_req\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mparams\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43masync_req\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 151\u001B[0m \u001B[43m \u001B[49m\u001B[43m_return_http_data_only\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mparams\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m_return_http_data_only\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 152\u001B[0m \u001B[43m \u001B[49m\u001B[43m_preload_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mparams\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m_preload_content\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43;01mTrue\u001B[39;49;00m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 153\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_timeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mparams\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m_request_timeout\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 154\u001B[0m \u001B[43m \u001B[49m\u001B[43mcollection_formats\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mcollection_formats\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/api_client.py:316\u001B[0m, in \u001B[0;36mApiClient.call_api\u001B[0;34m(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, async_req, _return_http_data_only, collection_formats, _preload_content, _request_timeout)\u001B[0m\n\u001B[1;32m 279\u001B[0m \u001B[38;5;124;03m\"\"\"Makes the HTTP request (synchronous) and returns deserialized data.\u001B[39;00m\n\u001B[1;32m 280\u001B[0m \n\u001B[1;32m 281\u001B[0m \u001B[38;5;124;03mTo make an async request, set the async_req parameter.\u001B[39;00m\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 313\u001B[0m \u001B[38;5;124;03m then the method will return the response directly.\u001B[39;00m\n\u001B[1;32m 314\u001B[0m \u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m 315\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m async_req:\n\u001B[0;32m--> 316\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m__call_api\u001B[49m\u001B[43m(\u001B[49m\u001B[43mresource_path\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 317\u001B[0m \u001B[43m \u001B[49m\u001B[43mpath_params\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mheader_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 318\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mfiles\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 319\u001B[0m \u001B[43m \u001B[49m\u001B[43mresponse_type\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mauth_settings\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 320\u001B[0m \u001B[43m \u001B[49m\u001B[43m_return_http_data_only\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mcollection_formats\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 321\u001B[0m \u001B[43m \u001B[49m\u001B[43m_preload_content\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43m_request_timeout\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 322\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m 323\u001B[0m thread \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mpool\u001B[38;5;241m.\u001B[39mapply_async(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m__call_api, (resource_path,\n\u001B[1;32m 324\u001B[0m method, path_params, query_params,\n\u001B[1;32m 325\u001B[0m header_params, body,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 329\u001B[0m collection_formats,\n\u001B[1;32m 330\u001B[0m _preload_content, _request_timeout))\n", + "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/api_client.py:148\u001B[0m, in \u001B[0;36mApiClient.__call_api\u001B[0;34m(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, _return_http_data_only, collection_formats, _preload_content, _request_timeout)\u001B[0m\n\u001B[1;32m 145\u001B[0m url \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mconfiguration\u001B[38;5;241m.\u001B[39mhost \u001B[38;5;241m+\u001B[39m resource_path\n\u001B[1;32m 147\u001B[0m \u001B[38;5;66;03m# perform request and return response\u001B[39;00m\n\u001B[0;32m--> 148\u001B[0m response_data \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 149\u001B[0m \u001B[43m \u001B[49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mquery_params\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mheader_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 150\u001B[0m \u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mpost_params\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 151\u001B[0m \u001B[43m \u001B[49m\u001B[43m_preload_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_preload_content\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 152\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_timeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_request_timeout\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 154\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mlast_response \u001B[38;5;241m=\u001B[39m response_data\n\u001B[1;32m 156\u001B[0m return_data \u001B[38;5;241m=\u001B[39m response_data\n", + "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/api_client.py:366\u001B[0m, in \u001B[0;36mApiClient.request\u001B[0;34m(self, method, url, query_params, headers, post_params, body, _preload_content, _request_timeout)\u001B[0m\n\u001B[1;32m 358\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mrest_client\u001B[38;5;241m.\u001B[39mPOST(url,\n\u001B[1;32m 359\u001B[0m query_params\u001B[38;5;241m=\u001B[39mquery_params,\n\u001B[1;32m 360\u001B[0m headers\u001B[38;5;241m=\u001B[39mheaders,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 363\u001B[0m _request_timeout\u001B[38;5;241m=\u001B[39m_request_timeout,\n\u001B[1;32m 364\u001B[0m body\u001B[38;5;241m=\u001B[39mbody)\n\u001B[1;32m 365\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m method \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mPUT\u001B[39m\u001B[38;5;124m\"\u001B[39m:\n\u001B[0;32m--> 366\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrest_client\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mPUT\u001B[49m\u001B[43m(\u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 367\u001B[0m \u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mquery_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 368\u001B[0m \u001B[43m \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mheaders\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 369\u001B[0m \u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mpost_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 370\u001B[0m \u001B[43m \u001B[49m\u001B[43m_preload_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_preload_content\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 371\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_timeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_request_timeout\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 372\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mbody\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 373\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m method \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mPATCH\u001B[39m\u001B[38;5;124m\"\u001B[39m:\n\u001B[1;32m 374\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mrest_client\u001B[38;5;241m.\u001B[39mPATCH(url,\n\u001B[1;32m 375\u001B[0m query_params\u001B[38;5;241m=\u001B[39mquery_params,\n\u001B[1;32m 376\u001B[0m headers\u001B[38;5;241m=\u001B[39mheaders,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 379\u001B[0m _request_timeout\u001B[38;5;241m=\u001B[39m_request_timeout,\n\u001B[1;32m 380\u001B[0m body\u001B[38;5;241m=\u001B[39mbody)\n", + "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/rest.py:273\u001B[0m, in \u001B[0;36mRESTClientObject.PUT\u001B[0;34m(self, url, headers, query_params, post_params, body, _preload_content, _request_timeout)\u001B[0m\n\u001B[1;32m 271\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mPUT\u001B[39m(\u001B[38;5;28mself\u001B[39m, url, headers\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, query_params\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, post_params\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m,\n\u001B[1;32m 272\u001B[0m body\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, _preload_content\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m, _request_timeout\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m):\n\u001B[0;32m--> 273\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mPUT\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 274\u001B[0m \u001B[43m \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mheaders\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 275\u001B[0m \u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mquery_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 276\u001B[0m \u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mpost_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 277\u001B[0m \u001B[43m \u001B[49m\u001B[43m_preload_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_preload_content\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 278\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_timeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_request_timeout\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 279\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mbody\u001B[49m\u001B[43m)\u001B[49m\n", + "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/rest.py:222\u001B[0m, in \u001B[0;36mRESTClientObject.request\u001B[0;34m(self, method, url, query_params, headers, body, post_params, _preload_content, _request_timeout)\u001B[0m\n\u001B[1;32m 219\u001B[0m logger\u001B[38;5;241m.\u001B[39mdebug(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mresponse body: \u001B[39m\u001B[38;5;132;01m%s\u001B[39;00m\u001B[38;5;124m\"\u001B[39m, r\u001B[38;5;241m.\u001B[39mdata)\n\u001B[1;32m 221\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;241m200\u001B[39m \u001B[38;5;241m<\u001B[39m\u001B[38;5;241m=\u001B[39m r\u001B[38;5;241m.\u001B[39mstatus \u001B[38;5;241m<\u001B[39m\u001B[38;5;241m=\u001B[39m \u001B[38;5;241m299\u001B[39m:\n\u001B[0;32m--> 222\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m ApiException(http_resp\u001B[38;5;241m=\u001B[39mr)\n\u001B[1;32m 224\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m r\n", + "\u001B[0;31mApiException\u001B[0m: (400)\nReason: Bad Request\nHTTP response headers: HTTPHeaderDict({'transfer-encoding': 'chunked', 'Vary': 'Origin, Access-Control-Request-Method, Access-Control-Request-Headers', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '1; mode=block', 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'X-Frame-Options': 'DENY', 'Content-Type': 'application/json', 'Date': 'Sat, 23 Jul 2022 10:53:23 GMT'})\nHTTP response body: b'{\"status\":\"BAD_REQUEST\",\"message\":\"Query not valid for this database\",\"code\":\"error.query.malformed\"}'\n" + ] + } + ], + "source": [ + "response = query.execute({\n", + " \"statement\": \"select `date`, `location`, `parameter`, `interval`, `unit`, `value`, `status` from `\" + table_internal_name + \"` where `foo` = 'bar'\"\n", + "}, container_id, database_id, page=0, size=3)\n", + "print(response)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} \ No newline at end of file diff --git a/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerDatabaseEndpoint.java b/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerDatabaseEndpoint.java index 66785334812ba2c7439d01336dbe31bd6c22e98c..31601a915fbd3afea94a8fa14be8ed6b12f4614f 100644 --- a/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerDatabaseEndpoint.java +++ b/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerDatabaseEndpoint.java @@ -8,7 +8,6 @@ import at.tuwien.entities.database.Database; import at.tuwien.exception.*; import at.tuwien.mapper.DatabaseMapper; import at.tuwien.service.MessageQueueService; -import at.tuwien.service.QueryStoreService; import at.tuwien.service.impl.MariaDbServiceImpl; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; @@ -34,15 +33,13 @@ public class ContainerDatabaseEndpoint { private final DatabaseMapper databaseMapper; private final MariaDbServiceImpl databaseService; - private final QueryStoreService queryStoreService; private final MessageQueueService messageQueueService; @Autowired public ContainerDatabaseEndpoint(DatabaseMapper databaseMapper, MariaDbServiceImpl databaseService, - QueryStoreService queryStoreService, MessageQueueService messageQueueService) { + MessageQueueService messageQueueService) { this.databaseMapper = databaseMapper; this.databaseService = databaseService; - this.queryStoreService = queryStoreService; this.messageQueueService = messageQueueService; } @@ -78,11 +75,10 @@ public class ContainerDatabaseEndpoint { @Valid @RequestBody DatabaseCreateDto createDto, Principal principal) throws ImageNotSupportedException, ContainerNotFoundException, DatabaseMalformedException, - AmqpException, ContainerConnectionException, UserNotFoundException, QueryStoreException, - DatabaseNotFoundException, DatabaseNameExistsException { + AmqpException, ContainerConnectionException, UserNotFoundException, + DatabaseNotFoundException, DatabaseNameExistsException, DatabaseConnectionException { final Database database = databaseService.create(containerId, createDto, principal); messageQueueService.createExchange(database, principal); - queryStoreService.create(containerId, database.getId()); return ResponseEntity.status(HttpStatus.CREATED) .body(databaseMapper.databaseToDatabaseBriefDto(database)); } @@ -128,7 +124,7 @@ public class ContainerDatabaseEndpoint { @NotBlank @PathVariable Long databaseId, Principal principal) throws DatabaseNotFoundException, ImageNotSupportedException, DatabaseMalformedException, AmqpException, ContainerConnectionException, - ContainerNotFoundException { + ContainerNotFoundException, DatabaseConnectionException { final Database database = databaseService.findById(containerId, databaseId); messageQueueService.deleteExchange(database); databaseService.delete(containerId, databaseId, principal); diff --git a/fda-database-service/rest-service/src/main/resources/querystore.sql b/fda-database-service/rest-service/src/main/resources/querystore.sql new file mode 100644 index 0000000000000000000000000000000000000000..19f38a3d74a89764d183095adf7748ee81a9b94f --- /dev/null +++ b/fda-database-service/rest-service/src/main/resources/querystore.sql @@ -0,0 +1,35 @@ +-- SEQUENCES +CREATE SEQUENCE `qs_tables_seq`; +CREATE SEQUENCE `qs_columns_seq`; +CREATE SEQUENCE `qs_columns_seq`; + +-- TABLES +CREATE TABLE `qs_queries` +( + `id` bigint not null primary key default nextval(`qs_queries_seq`), + `cid` bigint not null, + `created` datetime not null, + `created_by` bigint not null, + `dbid` bigint not null, + `execution` datetime not null, + `last_modified` datetime not null, + `query` text not null, + `query_hash` varchar(255) not null, + `result_hash` varchar(255), + `result_number` bigint +); +CREATE TABLE `qs_tables` +( + `id` bigint not null primary key default nextval(`qs_tables_seq`), + `created` datetime not null, + `dbid` bigint not null, + `last_modified` datetime +); +CREATE TABLE `qs_columns` +( + `id` bigint not null primary key default nextval(`qs_columns_seq`), + `created` datetime not null, + `dbid` bigint not null, + `tid` bigint not null, + `last_modified` datetime +); \ No newline at end of file diff --git a/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java b/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java index 425dc223223cbf950fee17d79f55b6e5b4dda7d9..3537f5a9ae30f90647f005f32180a90e047bda0f 100644 --- a/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java +++ b/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java @@ -7,6 +7,7 @@ import at.tuwien.api.database.LanguageTypeDto; import at.tuwien.api.user.UserDetailsDto; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.LanguageType; +import at.tuwien.querystore.Query; import org.apache.http.auth.BasicUserPrincipal; import org.mapstruct.Mapper; import org.mapstruct.Mapping; diff --git a/fda-database-service/services/src/main/java/at/tuwien/service/DatabaseService.java b/fda-database-service/services/src/main/java/at/tuwien/service/DatabaseService.java index 31d638e39ccef219914e91f63cb53d411ba30bc8..97986772568893c061e2822ce58faf31519beb37 100644 --- a/fda-database-service/services/src/main/java/at/tuwien/service/DatabaseService.java +++ b/fda-database-service/services/src/main/java/at/tuwien/service/DatabaseService.java @@ -63,7 +63,7 @@ public interface DatabaseService { */ void delete(Long id, Long databaseId, Principal principal) throws DatabaseNotFoundException, ImageNotSupportedException, - DatabaseMalformedException, AmqpException, ContainerConnectionException, ContainerNotFoundException; + DatabaseMalformedException, AmqpException, ContainerConnectionException, ContainerNotFoundException, DatabaseConnectionException; /** * Creates a new database with minimal metadata in the metadata database and creates a new database on the container. @@ -80,7 +80,7 @@ public interface DatabaseService { */ Database create(Long id, DatabaseCreateDto createDto, Principal principal) throws ImageNotSupportedException, ContainerNotFoundException, - DatabaseMalformedException, AmqpException, ContainerConnectionException, UserNotFoundException, DatabaseNameExistsException; + DatabaseMalformedException, AmqpException, ContainerConnectionException, UserNotFoundException, DatabaseNameExistsException, DatabaseConnectionException; /** * Updates the database metadata. diff --git a/fda-database-service/services/src/main/java/at/tuwien/service/QueryStoreService.java b/fda-database-service/services/src/main/java/at/tuwien/service/QueryStoreService.java deleted file mode 100644 index 2cd4393139da368641f141775f34c0bc32f44436..0000000000000000000000000000000000000000 --- a/fda-database-service/services/src/main/java/at/tuwien/service/QueryStoreService.java +++ /dev/null @@ -1,20 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.exception.DatabaseNotFoundException; -import at.tuwien.exception.ImageNotSupportedException; -import at.tuwien.exception.QueryStoreException; - -public interface QueryStoreService { - - /** - * Creates the query store by executing a query, the Hibernate session is configured to automatically create the necessary table. - * - * @param containerId The container id. - * @param databaseId The database id. - * @throws DatabaseNotFoundException The database was not found in the metadata database. - * @throws ImageNotSupportedException The image is not supported, currently we only support MariaDB. - * @throws QueryStoreException The query store failed to create. - */ - void create(Long containerId, Long databaseId) throws DatabaseNotFoundException, - ImageNotSupportedException, QueryStoreException; -} diff --git a/fda-database-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java b/fda-database-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java index 1226866d4aadd050153c3ab544470af7cd93f512..cc7b682015709828d1cff623d54e20ff5e5c17af 100644 --- a/fda-database-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java +++ b/fda-database-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java @@ -5,18 +5,18 @@ import at.tuwien.entities.container.image.ContainerImage; import at.tuwien.entities.container.image.ContainerImageEnvironmentItem; import at.tuwien.entities.container.image.ContainerImageEnvironmentItemType; import at.tuwien.entities.database.Database; -import at.tuwien.querystore.Column; -import at.tuwien.querystore.Query; -import at.tuwien.querystore.Table; +import at.tuwien.exception.DatabaseConnectionException; +import com.mchange.v2.c3p0.ComboPooledDataSource; import lombok.extern.log4j.Log4j2; import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.cfg.Configuration; import org.hibernate.query.NativeQuery; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import javax.persistence.PersistenceException; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; import java.util.List; import java.util.stream.Collectors; @@ -24,54 +24,68 @@ import java.util.stream.Collectors; @Service public abstract class HibernateConnector { - protected static Session getCurrentSession(ContainerImage image, Container container) { - return getCurrentSession(image, container, null); + protected static Connection getConnection(ContainerImage image, Container container) throws DatabaseConnectionException { + return getConnection(image, container, null); } - protected static Session getCurrentSession(ContainerImage image, Container container, Database database) { + protected static Connection getConnection(ContainerImage image, Container container, Database database) throws DatabaseConnectionException { + final ComboPooledDataSource dataSource = new ComboPooledDataSource(); final String url = "jdbc:" + image.getJdbcMethod() + "://" + container.getInternalName() + "/" + (database != null ? database.getInternalName() : ""); + dataSource.setJdbcUrl(url); final String username = image.getEnvironment() .stream() .filter(e -> e.getType().equals(ContainerImageEnvironmentItemType.PRIVILEGED_USERNAME)) .map(ContainerImageEnvironmentItem::getValue) .collect(Collectors.toList()) .get(0); + dataSource.setUser(username); final String password = image.getEnvironment() .stream() .filter(e -> e.getType().equals(ContainerImageEnvironmentItemType.PRIVILEGED_PASSWORD)) .map(ContainerImageEnvironmentItem::getValue) .collect(Collectors.toList()) .get(0); - final Configuration config = new Configuration(); - config.configure("mariadb_hibernate.cfg.xml"); - config.setProperty("hibernate.connection.url", url); - config.setProperty("hibernate.connection.username", username); - config.setProperty("hibernate.connection.password", password); - config.setProperty("hibernate.connection.driver_class", image.getDriverClass()); - config.setProperty("hibernate.dialect", image.getDialect()); - final SessionFactory sessionFactory = config.buildSessionFactory(); - Session session = sessionFactory.getCurrentSession(); - if (!session.isOpen()) { - log.warn("Session is closed, opening..."); - session = sessionFactory.openSession(); + dataSource.setPassword(password); + dataSource.setInitialPoolSize(5); + dataSource.setMinPoolSize(5); + dataSource.setAcquireIncrement(5); + dataSource.setMaxPoolSize(20); + dataSource.setMaxStatements(100); + final Connection connection; + try { + connection = dataSource.getConnection(); + } catch (SQLException e) { + log.error("Failed to connect to the database"); + log.debug("failed to connect to the database {}", database); + throw new DatabaseConnectionException("Failed to connect to the database"); } - return session; + return connection; } - protected static Long activeConnection(Session session) { - final NativeQuery<?> nativeQuery = session.createSQLQuery("SHOW STATUS LIKE 'threads_connected'"); - final List<?> result; + protected static Long activeConnection(Connection connection) throws DatabaseConnectionException { + final ResultSet resultSet = execute(connection, "SHOW STATUS LIKE 'threads_connected'"); try { - result = nativeQuery.getResultList(); - } catch (PersistenceException e) { - log.error("Failed to collect number of used connections"); - /* ignore */ - return null; + if (resultSet.next()) { + return resultSet.getLong(2); + } + } catch (SQLException e) { + log.error("Failed to determine active connections"); + throw new DatabaseConnectionException("Failed to determine active connections", e); } - final Object[] row = (Object[]) result.get(0); - log.debug("current number of connections: {}", Long.parseLong(String.valueOf(row[1]))); - return Long.parseLong(String.valueOf(row[1])); + log.error("Failed to determine active connections"); + throw new DatabaseConnectionException("Failed to determine active connections"); } + protected static ResultSet execute(Connection connection, String statement) throws DatabaseConnectionException { + final PreparedStatement preparedStatement; + try { + preparedStatement = connection.prepareStatement(statement); + return preparedStatement.executeQuery(); + } catch (SQLException e) { + log.error("Failed to execute statement"); + log.debug("failed to execute statement {}", statement); + throw new DatabaseConnectionException("Failed to execute statement", e); + } + } } diff --git a/fda-database-service/services/src/main/java/at/tuwien/service/impl/MariaDbServiceImpl.java b/fda-database-service/services/src/main/java/at/tuwien/service/impl/MariaDbServiceImpl.java index b89eeddbc634d22809d58d9ebdd9b4bfed11cf64..2160174133acd4ccb05cd604f0bb4b2681722f78 100644 --- a/fda-database-service/services/src/main/java/at/tuwien/service/impl/MariaDbServiceImpl.java +++ b/fda-database-service/services/src/main/java/at/tuwien/service/impl/MariaDbServiceImpl.java @@ -27,6 +27,9 @@ import org.springframework.transaction.annotation.Transactional; import javax.persistence.PersistenceException; import java.security.Principal; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.time.Instant; import java.util.List; import java.util.Optional; @@ -101,29 +104,16 @@ public class MariaDbServiceImpl extends HibernateConnector implements DatabaseSe @Transactional public void delete(Long containerId, Long databaseId, Principal principal) throws DatabaseNotFoundException, ImageNotSupportedException, DatabaseMalformedException, ContainerConnectionException, AmqpException, - ContainerNotFoundException { + ContainerNotFoundException, DatabaseConnectionException { final Container container = containerService.find(containerId); final Database database = findPublicOrMineById(containerId, databaseId, principal); if (!database.getContainer().getImage().getRepository().equals("mariadb")) { throw new ImageNotSupportedException("Currently only MariaDB is supported"); } /* run query */ - final Session session = getCurrentSession(container.getImage(), container, database); - final Transaction transaction = session.beginTransaction(); - final NativeQuery<?> query = session.createSQLQuery(databaseMapper.databaseToRawDeleteDatabaseQuery(database)); - try { - log.debug("query affected {} rows", query.executeUpdate()); - activeConnection(session); - transaction.commit(); - } catch (ServiceException e) { - log.error("Failed to delete database."); - session.close(); - throw new DatabaseMalformedException("Failed to delete database", e); - } finally { - if (session.isOpen()) { - session.close(); - } - } + final Connection connection = getConnection(container.getImage(), container, database); + execute(connection, databaseMapper.databaseToRawDeleteDatabaseQuery(database)); + activeConnection(connection); database.setDeleted(Instant.now()) /* method has void, only for debug logs */; /* save in metadata database */ databaseRepository.deleteById(databaseId); @@ -135,7 +125,8 @@ public class MariaDbServiceImpl extends HibernateConnector implements DatabaseSe @Transactional public Database create(Long containerId, DatabaseCreateDto createDto, Principal principal) throws ImageNotSupportedException, ContainerNotFoundException, - DatabaseMalformedException, AmqpException, ContainerConnectionException, UserNotFoundException, DatabaseNameExistsException { + DatabaseMalformedException, AmqpException, ContainerConnectionException, UserNotFoundException, + DatabaseNameExistsException, DatabaseConnectionException { final Container container = containerService.find(containerId); if (container.getDatabases().size() != 0) { log.error("Currently we only support one database per container."); @@ -146,31 +137,13 @@ public class MariaDbServiceImpl extends HibernateConnector implements DatabaseSe database.setName(createDto.getName()); database.setInternalName(databaseMapper.nameToInternalName(database.getName())); database.setContainer(container); - /* run query */ - final Session session = getCurrentSession(container.getImage(), container); - final Transaction transaction = session.beginTransaction(); - final NativeQuery<?> query = session.createSQLQuery(databaseMapper.databaseToRawCreateDatabaseQuery(database)); - try { - log.debug("query affected {} rows", query.executeUpdate()); - } catch (PersistenceException e) { - log.error("Failed to create database"); - log.debug("failed to create database: {}", e.getMessage()); - session.close(); - throw new DatabaseNameExistsException("Failed to create database", e); - } - final NativeQuery<?> grant = session.createSQLQuery(databaseMapper.imageToRawGrantReadonlyAccessQuery()); - try { - log.debug("grant affected {} rows", grant.executeUpdate()); - activeConnection(session); - transaction.commit(); - } catch (PersistenceException e) { - log.error("Failed to grant privileges."); - throw new DatabaseMalformedException("Failed to grant privileges", e); - } finally { - if (session.isOpen()) { - session.close(); - } - } + /* create database */ + final Connection connection = getConnection(container.getImage(), container); + execute(connection, databaseMapper.databaseToRawCreateDatabaseQuery(database)); + log.debug("active database connections {}", activeConnection(connection)); + /* grant read-only access */ + execute(connection, databaseMapper.imageToRawGrantReadonlyAccessQuery()); + log.debug("active database connections {}", activeConnection(connection)); /* save in metadata database */ database.setExchange(amqpMapper.exchangeName(database)); database.setDescription(createDto.getDescription()); diff --git a/fda-database-service/services/src/main/java/at/tuwien/service/impl/QueryStoreServiceImpl.java b/fda-database-service/services/src/main/java/at/tuwien/service/impl/QueryStoreServiceImpl.java deleted file mode 100644 index 5258ebbce18f069806a79ad48f5f155d69993c33..0000000000000000000000000000000000000000 --- a/fda-database-service/services/src/main/java/at/tuwien/service/impl/QueryStoreServiceImpl.java +++ /dev/null @@ -1,56 +0,0 @@ -package at.tuwien.service.impl; - -import at.tuwien.entities.database.Database; -import at.tuwien.exception.DatabaseNotFoundException; -import at.tuwien.exception.ImageNotSupportedException; -import at.tuwien.exception.QueryStoreException; -import at.tuwien.service.DatabaseService; -import at.tuwien.service.QueryStoreService; -import lombok.extern.log4j.Log4j2; -import org.hibernate.Session; -import org.hibernate.Transaction; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import javax.persistence.PersistenceException; - -@Log4j2 -@Service -public class QueryStoreServiceImpl extends HibernateConnector implements QueryStoreService { - - private final DatabaseService databaseService; - - @Autowired - public QueryStoreServiceImpl(DatabaseService databaseService) { - this.databaseService = databaseService; - } - - @Override - public void create(Long containerId, Long databaseId) throws DatabaseNotFoundException, - ImageNotSupportedException, QueryStoreException { - /* find */ - final Database database = databaseService.findById(containerId, databaseId); - if (!database.getContainer().getImage().getRepository().equals("mariadb")) { - throw new ImageNotSupportedException("Currently only MariaDB is supported"); - } - /* run query */ - final Session session = getCurrentSession(database.getContainer().getImage(), database.getContainer(), database); - final Transaction transaction = session.beginTransaction(); - /* use jpq to select all */ - final org.hibernate.query.Query<at.tuwien.querystore.Query> queries = session.createQuery("select q from Query q", - at.tuwien.querystore.Query.class); - try { - queries.getResultList(); - activeConnection(session); - transaction.commit(); - } catch (PersistenceException e) { - log.error("Failed to find all queries"); - session.close(); - throw new QueryStoreException("Failed to find all queries"); - } finally { - if (session.isOpen()) { - session.close(); - } - } - } -}