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

feat: third party app support in EVADB #1033

Merged
Merged
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
761aaae
Merge branch 'master' of github.com:georgia-tech-db/eva
gaurav274 Aug 25, 2023
826d3a1
Merge branch 'master' of github.com:georgia-tech-db/eva
gaurav274 Aug 26, 2023
8bc42d7
Merge branch 'master' of github.com:georgia-tech-db/eva
gaurav274 Aug 26, 2023
607e5d6
docs: add logo
jarulraj Aug 28, 2023
ad6dc03
docs: Update README.md
jarulraj Aug 28, 2023
fca3c74
Merge branch 'master' of github.com:georgia-tech-db/eva
gaurav274 Aug 29, 2023
8137fed
Merge branch 'staging' of github.com:georgia-tech-db/eva into staging
gaurav274 Aug 29, 2023
aa92883
Merge branch 'staging'
gaurav274 Aug 29, 2023
9c0af83
[RELEASE]: v0.3.3 (#984)
gaurav274 Aug 29, 2023
9a4e908
initial changes
Sep 2, 2023
e9f0a58
linter fixes
Sep 2, 2023
315cfac
fix failing tests
Sep 2, 2023
6dcc434
Merge branch 'staging' into evaql-slack-integration
Sep 2, 2023
262cf98
restructure handlers
Sep 2, 2023
4f60106
linter fixes
Sep 2, 2023
9dd32d6
finished code changes
Sep 2, 2023
e70e8fe
linter fixes
Sep 2, 2023
82df32e
remove dedup
Sep 6, 2023
d1bea8d
linter fixes
Sep 6, 2023
c6fb81c
missed change
Sep 6, 2023
e706a3d
restructure
Sep 7, 2023
5b6619b
linter fixes
Sep 7, 2023
d5513c7
add handler functionality
Sep 7, 2023
074b59c
linter fixes
Sep 7, 2023
077ceec
Merge branch 'staging' into evaql-slack-integration
Sep 7, 2023
0c83538
test fix
Sep 7, 2023
9a964b6
lint fixes
Sep 7, 2023
8ced568
lint fix
Sep 8, 2023
8b0646c
review comments
Sep 17, 2023
e9b3fbb
linter fixes
Sep 17, 2023
af939cf
fix test failure
Sep 17, 2023
0ef5d55
Merge branch 'staging' into evaql-slack-integration
Sep 17, 2023
1dce237
merge fixes
Sep 17, 2023
a0c2f0e
test fixes
Sep 17, 2023
c89b68e
undo change
Sep 17, 2023
7d054ee
linter fixes
Sep 17, 2023
0791783
Merge branch 'staging' into evaql-slack-integration
Sep 20, 2023
f43268b
review comments
Sep 20, 2023
5e0cc92
Merge branch 'staging' into evaql-slack-integration
Sep 22, 2023
75cac74
merge fixes
Sep 22, 2023
fec33c7
Merge branch 'staging' into evaql-slack-integration
Sep 26, 2023
b879b55
reduce PR size
Nov 3, 2023
a5d5d84
reduce PR size further
Nov 3, 2023
a6551f3
reduce PR size more
Nov 3, 2023
5c6f2da
remove whitespace
Nov 3, 2023
4529943
Merge branch 'staging' into evaql-slack-integration
Nov 3, 2023
876080e
pull some changes
Nov 3, 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
Prev Previous commit
Next Next commit
restructure handlers
Kaushik Ravichandran committed Sep 2, 2023
commit 262cf9880a0e502bda5b260d64af9ac3cb301a8f
20 changes: 16 additions & 4 deletions evadb/executor/create_application_executor.py
Original file line number Diff line number Diff line change
@@ -16,25 +16,37 @@

from evadb.database import EvaDBDatabase
from evadb.executor.abstract_executor import AbstractExecutor
from evadb.executor.executor_utils import ExecutorError
from evadb.models.storage.batch import Batch
from evadb.parser.create_statement import CreateApplicationStatement
from evadb.third_party.applications.interface import get_application_handler
from evadb.utils.logging_manager import logger



class CreateApplicationExecutor(AbstractExecutor):
def __init__(self, db: EvaDBDatabase, node: CreateApplicationStatement):
super().__init__(db, node)

def exec(self, *args, **kwargs):
# todo handle if_not_exists

logger.debug(
f"Trying to connect to the provided engine {self.node.engine} with params {self.node.param_dict}"
)
# todo handle if the provided application params are valid

logger.debug(f"Creating application {self.node}")
# Check if application already exists.
app_catalog_entry = self.catalog().get_application_catalog_entry(
self.node.application_name
)
if app_catalog_entry is not None:
raise ExecutorError(f"{self.node.application_name} already exists.")

# Check the validity of application entry.
handler = get_application_handler(self.node.engine, **self.node.param_dict)
resp = handler.connect()
if not resp.status:
raise ExecutorError(f"Cannot establish connection due to {resp.error}")

logger.debug(f"Creating application {self.node}")
self.catalog().insert_application_catalog_entry(
self.node.application_name, self.node.engine, self.node.param_dict
)
41 changes: 41 additions & 0 deletions evadb/third_party/applications/interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# coding=utf-8
# Copyright 2018-2023 EvaDB
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import importlib
import os

def get_application_handler(engine: str, **kwargs):
"""
Return the application handler. User should modify this function for
their new integrated handlers.
"""

# Dynamically import the top module.
try:
mod = dynamic_import(engine)
except ImportError:
req_file = os.path.join(os.path.dirname(__file__), engine, "requirements.txt")
if os.path.isfile(req_file):
with open(req_file) as f:
raise ImportError(f"Please install the following packages {f.read()}")

if engine == "slack":
return mod.SlackHandler(engine, **kwargs)
else:
raise NotImplementedError(f"Engine {engine} is not supported")


def dynamic_import(handler_dir):
import_path = f"evadb.third_party.applications.{handler_dir}.{handler_dir}_handler"
return importlib.import_module(import_path)
15 changes: 15 additions & 0 deletions evadb/third_party/applications/slack/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# coding=utf-8
# Copyright 2018-2023 EvaDB
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""third party/applications/slack"""
4 changes: 4 additions & 0 deletions evadb/third_party/applications/slack/slack_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@


class SlackHandler():
pass
129 changes: 129 additions & 0 deletions evadb/third_party/applications/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# coding=utf-8
# Copyright 2018-2023 EvaDB
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from dataclasses import dataclass
from evadb.third_party.types import ThirdPartyResponse, ThirdPartyStatus, ThirdPartyHandler
import pandas as pd


@dataclass
class AppHandlerResponse (ThirdPartyResponse):
"""
Represents the response from a database handler containing data and an optional error message.

Attributes:
data (pd.DataFrame): A Pandas DataFrame containing the data retrieved from the database.
error (str, optional): An optional error message indicating any issues encountered during the operation.
"""

data: pd.DataFrame
error: str = None


@dataclass
class AppHandlerStatus (ThirdPartyStatus):
"""
Represents the status of a database handler operation, along with an optional error message.

Attributes:
status (bool): A boolean indicating the success (True) or failure (False) of the operation.
error (str, optional): An optional error message providing details about any errors that occurred.
"""

status: bool
error: str = None


class AppHandler (ThirdPartyHandler):
"""
Base class for handling database operations.

Args:
name (str): The name associated with the database handler instance.
"""

def __init__(self, name: str, **kwargs):
self.name = name
self.connection = None

def connect(self):
"""
Establishes a connection to the database.

Raises:
NotImplementedError: This method should be implemented in derived classes.
"""
raise NotImplementedError()

def disconnect(self):
"""
Disconnects from the database.

This method can be overridden in derived classes to perform specific disconnect actions.
"""
raise NotImplementedError()

def check_connection(self) -> AppHandlerStatus:
"""
Checks the status of the database connection.

Returns:
AppHandlerStatus: An instance of AppHandlerStatus indicating the connection status.

Raises:
NotImplementedError: This method should be implemented in derived classes.
"""
raise NotImplementedError()

def get_tables(self) -> AppHandlerResponse:
"""
Retrieves the list of tables from the database.

Returns:
AppHandlerResponse: An instance of AppHandlerResponse containing the list of tables or an error message. Data is in a pandas DataFrame.

Raises:
NotImplementedError: This method should be implemented in derived classes.
"""
raise NotImplementedError()

def get_columns(self, table_name: str) -> AppHandlerResponse:
"""
Retrieves the columns of a specified table from the database.

Args:
table_name (str): The name of the table for which to retrieve columns.

Returns:
AppHandlerResponse: An instance of AppHandlerResponse containing the columns or an error message. Data is in a pandas DataFrame. It should have the following two columns: name and dtype. The dtype should be a Python dtype and will default to `str`.

Raises:
NotImplementedError: This method should be implemented in derived classes.
"""
raise NotImplementedError()

def execute_native_query(self, query_string: str) -> AppHandlerResponse:
"""
Executes the query through the handler's database engine.

Args:
query_string (str): The string representation of the native query.

Returns:
AppHandlerResponse: An instance of AppHandlerResponse containing the columns or an error message. Data is in a pandas DataFrame.

Raises:
NotImplementedError: This method should be implemented in derived classes.
"""
raise NotImplementedError()
8 changes: 4 additions & 4 deletions evadb/third_party/databases/types.py
Original file line number Diff line number Diff line change
@@ -13,12 +13,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from dataclasses import dataclass

from evadb.third_party.types import ThirdPartyResponse, ThirdPartyStatus, ThirdPartyHandler
import pandas as pd


@dataclass
class DBHandlerResponse:
class DBHandlerResponse (ThirdPartyResponse):
"""
Represents the response from a database handler containing data and an optional error message.

@@ -32,7 +32,7 @@ class DBHandlerResponse:


@dataclass
class DBHandlerStatus:
class DBHandlerStatus (ThirdPartyStatus):
"""
Represents the status of a database handler operation, along with an optional error message.

@@ -45,7 +45,7 @@ class DBHandlerStatus:
error: str = None


class DBHandler:
class DBHandler (ThirdPartyHandler):
"""
Base class for handling database operations.

93 changes: 93 additions & 0 deletions evadb/third_party/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# coding=utf-8
# Copyright 2018-2023 EvaDB
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from dataclasses import dataclass
@dataclass
class ThirdPartyResponse:
"""
Represents the response from a third party service handler
"""
pass

@dataclass
class ThirdPartyStatus:
"""
Represents the status of a third party service handler operation
"""
pass

class ThirdPartyHandler:
"""
Base class for handling third party service operations.

Args:
name (str): The name associated with the database handler instance.
"""

def __init__(self, name: str, **kwargs):
self.name = name
self.connection = None

def connect(self):
"""
Establishes a connection to the third party service.

Raises:
NotImplementedError: This method should be implemented in derived classes.
"""
raise NotImplementedError()

def disconnect(self):
"""
Disconnects from the third party service.

This method can be overridden in derived classes to perform specific disconnect actions.
"""
raise NotImplementedError()

def check_connection(self) -> ThirdPartyStatus:
"""
Checks the status of the connection.

Raises:
NotImplementedError: This method should be implemented in derived classes.
"""
raise NotImplementedError()

def get_tables(self) -> ThirdPartyResponse:
"""
Retrieves the list of tables.

Raises:
NotImplementedError: This method should be implemented in derived classes.
"""
raise NotImplementedError()

def get_columns(self, table_name: str) -> ThirdPartyResponse:
"""
Retrieves the columns of a specified table.

Raises:
NotImplementedError: This method should be implemented in derived classes.
"""
raise NotImplementedError()

def execute_native_query(self, query_string: str) -> ThirdPartyResponse:
"""
Executes the query through the handler's engine.

Raises:
NotImplementedError: This method should be implemented in derived classes.
"""
raise NotImplementedError()