From fc863c1db0679ca7a3d1f9856a8b6817d7df7bfb Mon Sep 17 00:00:00 2001 From: "Karl O. Pinc" Date: Fri, 13 Sep 2024 22:22:37 -0500 Subject: [PATCH] Move pgwui_core SQL related code into it's own module --- src/pgwui_core/core.py | 141 --------------------------------- src/pgwui_core/sql.py | 171 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 141 deletions(-) create mode 100644 src/pgwui_core/sql.py diff --git a/src/pgwui_core/core.py b/src/pgwui_core/core.py index d989c00..a5cd44f 100644 --- a/src/pgwui_core/core.py +++ b/src/pgwui_core/core.py @@ -51,110 +51,6 @@ from pgwui_core.constants import ( # Upload processing -@attrs.define(slots=False) -class SQLCommand(): - ''' - An SQL command or commands - - Attributes: - stmt The statement or statements, formatted for psycopg3 substitution - args Tuple of arguments used to substitute when executed. - ec(ex) Produces the exception to raise an instance of on failure - Input: - ex The exception raised by psycopg3 - ''' - stmt = attrs.field() - args = attrs.field() - ec = attrs.field(default=None) - - def _explain_encoding_error(self, ex): - '''Return a SQLEncodingError instance - ''' - if isinstance(ex, UnicodeEncodeError): - return core_ex.SQLEncodingError( - ex, - ("Data cannot be represented in the database" - " connection's client-side character encoding"), - (f'The SQL statement is ({self.stmt}) and the data supplied' - f' is ({self.tupl})')) - if isinstance(ex, psycopg.errors.UntranslatableCharacter): - return core_ex.SQLEncodingError( - ex, - ("Data cannot be represented in the" - " character encoding of the database"), - (f'The SQL statement is ({self.stmt}) and the data supplied' - f' is ({self.tupl})')) - return ex - - def execute(self, cur): - ''' - Execute the sql statement. - - Input: - cur A psycopg3 cursor - - Side effects: - Does something in the db. - Can raise a psycopg3 error - ''' - try: - cur.execute(self.stmt, self.args) - except UnicodeEncodeError as ex: - if self.ec is None: - raise self._explain_encoding_error(ex) - raise self.ec(self._explain_encoding_error(ex)) - except psycopg.errors.UntranslatableCharacter as ex: - if self.ec is None: - raise self._explain_encoding_error(ex) - raise self.ec(self._explain_encoding_error(ex)) - except psycopg.errors.DatabaseError as ex: - if self.ec is None: - raise ex - raise self.ec(ex) - - -@attrs.define(slots=False) -class LogSQLCommand(SQLCommand): - '''An SQL command that logs success or failure. - - Attributes: - stmt The statement, formatted for psycopg3 substitution - args Tuple of arguments used to substitute when executed. - ec(ex) Produces the exception to raise an instance of on failure - Input: - ex The exception raised by psycopg3 - log_success - Logs success - log_failure(ex) - Logs failure - Input: - ex The exception to log - ''' - log_success = attrs.field(default=None) - log_failure = attrs.field(default=None) - - def execute(self, cur): - ''' - Execute the sql statement. - - Input: - cur A psycopg3 cursor - - Side effects: - Does something in the db. - Can raise a psycopg3 error - ''' - try: - super().execute(cur) - except (core_ex.UploadError, psycopg.errors.DatabaseError) as ex: - if self.log_failure: - self.log_failure(ex) - raise - else: - if self.log_success: - self.log_success() - - class UploadLine(object): ''' Representation of a generic uploaded line @@ -254,25 +150,6 @@ class DBData(object): raise NotImplementedError() -class SQLData(DBData): - ''' - SQL statements returning no data that execute in the db. - - Attributes: - stmts List of SQLCommand instances - ''' - def __init__(self, stmts): - ''' - stmts List of SQLCommand instances - ''' - super().__init__() - self.stmts = stmts - - def _thunk(self): - for stmt in self.stmts: - yield lambda: stmt - - class UploadData(DBData): '''Uploaded data file @@ -535,24 +412,6 @@ class NoOpProcessor(DataLineProcessor): pass -class ExecuteSQL(DataLineProcessor): - def __init__(self, ue, uh): - ''' - ue UploadEngine instance - uh UploadHandler instance - cur psycopg3 cursor - ''' - super().__init__(ue, uh) - - def eat(self, sqlc): - ''' - Executes an sql command in the db. - - sqlc An SQLCommand instance (a command and it's args) - ''' - sqlc.execute(self.cur) - - @attrs.define(slots=False) class DBHandler(): ''' diff --git a/src/pgwui_core/sql.py b/src/pgwui_core/sql.py new file mode 100644 index 0000000..0e5e870 --- /dev/null +++ b/src/pgwui_core/sql.py @@ -0,0 +1,171 @@ +# Copyright (C) 2013, 2014, 2015, 2018, 2020, 2021, 2024 The Meme Factory, Inc. +# http://www.karlpinc.com/ + +# This file is part of PGWUI_Core. +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public +# License along with this program. If not, see +# . +# + +# Karl O. Pinc + +'''SQL execution facilities. +''' + +import attrs +import psycopg.errors + +from . import core +from . import exceptions as core_ex + + +@attrs.define(slots=False) +class SQLCommand(): + ''' + An SQL command or commands + + Attributes: + stmt The statement or statements, formatted for psycopg3 substitution + args Tuple of arguments used to substitute when executed. + ec(ex) Produces the exception to raise an instance of on failure + Input: + ex The exception raised by psycopg3 + ''' + stmt = attrs.field() + args = attrs.field() + ec = attrs.field(default=None) + + def _explain_encoding_error(self, ex): + '''Return a SQLEncodingError instance + ''' + if isinstance(ex, UnicodeEncodeError): + return core_ex.SQLEncodingError( + ex, + ("Data cannot be represented in the database" + " connection's client-side character encoding"), + (f'The SQL statement is ({self.stmt}) and the data supplied' + f' is ({self.tupl})')) + if isinstance(ex, psycopg.errors.UntranslatableCharacter): + return core_ex.SQLEncodingError( + ex, + ("Data cannot be represented in the" + " character encoding of the database"), + (f'The SQL statement is ({self.stmt}) and the data supplied' + f' is ({self.tupl})')) + return ex + + def execute(self, cur): + ''' + Execute the sql statement. + + Input: + cur A psycopg3 cursor + + Side effects: + Does something in the db. + Can raise a psycopg3 error + ''' + try: + cur.execute(self.stmt, self.args) + except UnicodeEncodeError as ex: + if self.ec is None: + raise self._explain_encoding_error(ex) + raise self.ec(self._explain_encoding_error(ex)) + except psycopg.errors.UntranslatableCharacter as ex: + if self.ec is None: + raise self._explain_encoding_error(ex) + raise self.ec(self._explain_encoding_error(ex)) + except psycopg.errors.DatabaseError as ex: + if self.ec is None: + raise ex + raise self.ec(ex) + + +@attrs.define(slots=False) +class LogSQLCommand(SQLCommand): + '''An SQL command that logs success or failure. + + Attributes: + stmt The statement, formatted for psycopg3 substitution + args Tuple of arguments used to substitute when executed. + ec(ex) Produces the exception to raise an instance of on failure + Input: + ex The exception raised by psycopg3 + log_success + Logs success + log_failure(ex) + Logs failure + Input: + ex The exception to log + ''' + log_success = attrs.field(default=None) + log_failure = attrs.field(default=None) + + def execute(self, cur): + ''' + Execute the sql statement. + + Input: + cur A psycopg3 cursor + + Side effects: + Does something in the db. + Can raise a psycopg3 error + ''' + try: + super().execute(cur) + except (core_ex.UploadError, psycopg.errors.DatabaseError) as ex: + if self.log_failure: + self.log_failure(ex) + raise + else: + if self.log_success: + self.log_success() + + +class SQLData(core.DBData): + ''' + SQL statements returning no data that execute in the db. + + Attributes: + stmts List of SQLCommand instances + ''' + def __init__(self, stmts): + ''' + stmts List of SQLCommand instances + ''' + super().__init__() + self.stmts = stmts + + def _thunk(self): + for stmt in self.stmts: + yield lambda: stmt + + +class ExecuteSQL(core.DataLineProcessor): + def __init__(self, ue, uh): + ''' + ue UploadEngine instance + uh UploadHandler instance + cur psycopg3 cursor + ''' + super().__init__(ue, uh) + + def eat(self, sqlc): + ''' + Executes an sql command in the db. + + sqlc An SQLCommand instance (a command and it's args) + ''' + sqlc.execute(self.cur) -- 2.34.1