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

Adding custom errors to Ocient engine spec #5

Merged
merged 3 commits into from
Jan 23, 2023
Merged
Changes from all commits
Commits
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
88 changes: 85 additions & 3 deletions superset/db_engine_specs/ocient.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,56 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
from typing import Optional, List

import re

from sqlalchemy.engine.reflection import Inspector
from superset.db_engine_specs.base import BaseEngineSpec
from superset.errors import SupersetErrorType
from flask_babel import gettext as __
alexclavel-ocient marked this conversation as resolved.
Show resolved Hide resolved

import pyocient
from pyocient import _STPoint, _STLinestring, _STPolygon, TypeCodes
from superset import app
from typing import Any, Callable, Dict, List, NamedTuple, Tuple

from superset.models.core import Database
from typing import Any, Callable, Dict, List, NamedTuple, Tuple, Optional, Pattern
# Ensure pyocient inherits Superset's logging level
superset_log_level = app.config['LOG_LEVEL']
pyocient.logger.setLevel(superset_log_level)


# Regular expressions to catch custom errors

CONNECTION_INVALID_USERNAME_REGEX = re.compile(
"The referenced user does not exist \(User \'(?P<username>.*?)\' not found\)"
)
CONNECTION_INVALID_PASSWORD_REGEX = re.compile(
'The userid/password combination was not valid \(Incorrect password for user\)'
)
CONNECTION_INVALID_HOSTNAME_REGEX = re.compile(
r"Unable to connect to (?P<host>.*?):(?P<port>.*?):"
)
CONNECTION_UNKNOWN_DATABASE_REGEX = re.compile(
"No database named '(?P<database>.*?)' exists"
)
CONNECTION_INVALID_PORT_ERROR = re.compile(
"Port out of range 0-65535"
)
INVALID_CONNECTION_STRING_REGEX = re.compile(
"An invalid connection string attribute was specified \(failed to decrypt cipher text\)"
)
SYNTAX_ERROR_REGEX = re.compile(
r"There is a syntax error in your statement \((?P<qualifier>.*?) input '(?P<input>.*?)' expecting {.*}"
)
TABLE_DOES_NOT_EXIST_REGEX = re.compile(
"The referenced table or view '(?P<table>.*?)' does not exist"
)
COLUMN_DOES_NOT_EXIST_REGEX = re.compile(
"The reference to column '(?P<column>.*?)' is not valid"
)

# Custom datatype conversion functions

def _to_hex(data: bytes) -> str:
"""
Converts the bytes object into a string of hexadecimal digits.
Expand Down Expand Up @@ -119,6 +154,53 @@ class OcientEngineSpec(BaseEngineSpec):
force_column_alias_quotes = True
max_column_name_length = 30

custom_errors : Dict[Pattern[str], Tuple[str, SupersetErrorType, Dict[str, Any]]] = {
CONNECTION_INVALID_USERNAME_REGEX: (
__('The username "%(username)s" does not exist.'),
SupersetErrorType.CONNECTION_INVALID_USERNAME_ERROR,
{},
),
CONNECTION_INVALID_PASSWORD_REGEX: (
__('The user/password combination is not valid (Incorrect password for user).'),
SupersetErrorType.CONNECTION_INVALID_PASSWORD_ERROR,
{},
),
CONNECTION_UNKNOWN_DATABASE_REGEX: (
__('Could not connect to database: "%(database)s"'),
SupersetErrorType.CONNECTION_UNKNOWN_DATABASE_ERROR,
{}
),
CONNECTION_INVALID_HOSTNAME_REGEX: (
__('Could not resolve hostname: "%(host)s".'),
SupersetErrorType.CONNECTION_INVALID_HOSTNAME_ERROR,
{}
),
CONNECTION_INVALID_PORT_ERROR: (
__('Port out of range 0-65535'),
SupersetErrorType.CONNECTION_INVALID_PORT_ERROR,
{}
),
INVALID_CONNECTION_STRING_REGEX: (
__('Invalid Connection String: Expecting String of the form \'ocient://user:pass@host:port/database\'.'),
SupersetErrorType.GENERIC_DB_ENGINE_ERROR,
{}
),
SYNTAX_ERROR_REGEX: (
__('Syntax Error: %(qualifier)s input "%(input)s".'),
SupersetErrorType.SYNTAX_ERROR,
{}
),
TABLE_DOES_NOT_EXIST_REGEX: (
__('Table or View "%(table)s" does not exist.'),
SupersetErrorType.TABLE_DOES_NOT_EXIST_ERROR,
{}
),
COLUMN_DOES_NOT_EXIST_REGEX: (
__('Invalid reference to column: "%(column)s"'),
SupersetErrorType.COLUMN_DOES_NOT_EXIST_ERROR,
{}
),
}
_time_grain_expressions = {
None: "{col}",
"PT1S": "ROUND({col}, 'SECOND')",
Expand Down