Client Reference Architecture
This is an outline of the Python reference archetecture for Mapepire
. The core components of the reference archetecture are the SQLJob
and Query
classes. The SQLJob
class manages the WebSocket connection to the server and provides methods to create and run queries. The Query
class manages the state of the query, sends it to the server, and fetches results.
Core Functions
SQL Job
High-Level Overview
The SQLJob
“class-like” object is designed to manage the client connection to the mapepire-server
. It handles the creation of unique identifiers for queries, manages WebSocket connections for sending and receiving data, and provides methods to create and run SQL queries. The class ensures that queries are executed in a controlled manner, maintaining their state and handling errors appropriately.
Class Definitions and Functions
class SQLJob: def __init__(self, options: Dict[Any, Any] = {}) -> None: """ Initialize a new instance of the class.
Args: options (Dict[Any, Any], optional): A dictionary of options for the job. Defaults to an empty dictionary.
Attributes: options (Dict[Any, Any]): Stores the options passed during initialization. _unique_id_counter (int): Counter for generating unique IDs. _reponse_emitter: Placeholder for a response emitter, initially set to None. _status (JobStatus): The current status of the job, initially set to NotStarted. _trace_file: Placeholder for a trace file, initially set to None. _is_tracing_channeldata (bool): Flag indicating whether channel data tracing is enabled, initially set to True. __unique_id: A unique identifier generated for the job. id (Optional[str]): An optional identifier for the job, initially set to None. """ self.options = options self._unique_id_counter: int = 0 self._reponse_emitter = None self._status: JobStatus = JobStatus.NotStarted self._trace_file = None self._is_tracing_channeldata: bool = True
self.__unique_id = self._get_unique_id("sqljob") self.id: Optional[str] = None
_get_unique_id(self, prefix: str = "id") -> str
-
Parameters:
- prefix (
str
): A string containing the prefix for the unique identifier.
- prefix (
-
Returns: (
str
) A unique identifier for a query.This function should update a counter for the number of queries executed and return a unique identifier for the query.
_get_channel(self, db2_server: DaemonServer) -> WebSocket
-
Parameters:
- db2_server (
Dict[str, Any]
): A dictionary-like object containing the connection information for the DB2 server. Here is a sample definition of theDaemonServer
class:
@dataclassclass DaemonServer:host: struser: strpassword: strport: intignoreUnauthorized: Optional[bool] = Noneca: Optional[Union[str, bytes]] = None - db2_server (
-
Returns: (
WebSocket
) A WebSocket connection to the DB2 server.This function is responsible for setting up a secure WebSocket connection to the
mapepire-server
. It constructs the connection URI, prepares the necessary headers for authentication, configures SSL options, and finally establishes the connection. The function returns the WebSocket object, which can then be used for communication with the server.
send(self, content: Any)
-
Parameters:
- content (
Any
): Any object that can be serialized into a JSON string.
- content (
-
Returns: None
This function is responsible for sending data to the
mapepire-server
over a WebSocket connection.
connect(self, db2_server: DaemonServer) -> Dict[Any, Any]
-
Parameters:
- db2_server (
DaemonServer
): A dictionary-like object containing the connection information for the DB2 server. Here is a sample definition of theDaemonServer
class:
@dataclassclass DaemonServer:host: struser: strpassword: strport: intignoreUnauthorized: Optional[bool] = Noneca: Optional[Union[str, bytes]] = None - db2_server (
-
Returns: (
Dict[str, Any]
) A dictionary-like object containing the response from the server.This function is responsible for establishing a connection to the
mapepire-server
. It calls the_get_channel(db2_server)
function to create a WebSocket connection, sends the connection request to the server, and waits for a response. The function returns the response from the server, which contains information about the connection status.
query(self, sql: str, opts: Optional[Union[Dict[str, Any], QueryOptions]] = None)
-
Parameters:
- sql (
str
): A string containing the SQL query to be executed. - opts (
Optional[Union[Dict[str, Any], QueryOptions]]
): A dictionary-like object containing additional options for the query. Here is a sample definition of theQueryOptions
class:
@dataclassclass QueryOptions:isTerseResults: Optional[bool] = NoneisClCommand: Optional[bool] = Noneparameters: Optional[List[str]] = NoneautoClose: Optional[bool] = None - sql (
-
Returns: (
Query
) AQuery
object representing the query to be executed.This function is responsible for creating a
Query
object that represents the SQL query to be executed. It constructs the query object with the provided SQL statement and any additional options. The function returns theQuery
object, which can then be used to run the query.
query_and_run(self, sql: str, opts: Optional[Union[Dict[str, Any], QueryOptions]] = None)
-
Parameters:
- sql (
str
): A string containing the SQL query to be executed. - opts (
Optional[Union[Dict[str, Any], QueryOptions]]
): A dictionary-like object containing additional options for the query.
- sql (
-
Returns: (
Query
) AQuery
object representing the query to be executed.This function is a convenience method that combines the
query
andrun
functions. It creates aQuery
object with the provided SQL statement and options, then immediately runs the query. The function returns theQuery
object, which can be used to fetch more data or close the query.
close(self)
-
Parameters: None
-
Returns: None
This function is responsible for closing the WebSocket connection to the DB2 server. It sends a close request to the server and waits for a response. Once the connection is closed, the function cleans up any resources associated with the connection.
Query
High-Level Overview
The Query
class-like object is designed to manage and execute SQL queries, handle their states, and fetch additional data. The Query
object inherits an SQLJob
instance and uses it’s WebSocket connection to send and receive data. See the Query Class definition below.
Class Definitions and Functions
class Query(Generic[T]): global_query_list: List["Query[Any]"] = []
def __init__(self, job: SQLJob, query: str, opts: QueryOptions) -> None: """ Initialize a new instance of the Query class.
Args: job (SQLJob): The SQL job associated with this query. query (str): The SQL query string. opts (QueryOptions): Options for configuring the query.
Attributes: job (SQLJob): Stores the SQL job associated with this query. is_prepared (bool): Indicates whether the query is prepared based on the presence of parameters. parameters (Optional[List[str]]): The parameters for the query, if any. sql (str): The SQL query string. is_cl_command (Optional[bool]): Indicates if the query is a command line command. should_auto_close (Optional[bool]): Indicates if the query should auto-close. is_terse_results (Optional[bool]): Indicates if the query should return terse results. _rows_to_fetch (int): The number of rows to fetch, default is 100. state (QueryState): The current state of the query, initially set to NOT_YET_RUN.
Class Attributes: global_query_list (List["Query[Any]"]): A global list of all Query instances. """ self.job = job self.is_prepared: bool = True if opts.parameters is not None else False self.parameters: Optional[List[str]] = opts.parameters self.sql: str = query self.is_cl_command: Optional[bool] = opts.isClCommand self.should_auto_close: Optional[bool] = opts.autoClose self.is_terse_results: Optional[bool] = opts.isTerseResults
self._rows_to_fetch: int = 100 self.state: QueryState = QueryState.NOT_YET_RUN
Query.global_query_list.append(self)
run(self, rows_to_fetch: Optional[int] = None) -> Dict[str, Any]
-
Parameters:
- rows_to_fetch (
Optional[int]
): An integer specifying the number of rows to fetch from the query result.
- rows_to_fetch (
-
Returns: (
Dict[str, Any]
) A dictionary-like object containing the response from the server.This function is responsible for executing the query and fetching the initial set of results. It sends the query to the server, waits for a response, and returns the result. If
rows_to_fetch
is specified, the function fetches the specified number of rows from the result set.
fetch_more(self, rows_to_fetch: Optional[int] = None) -> Dict[str, Any]
-
Parameters:
- rows_to_fetch (
Optional[int]
): An integer specifying the number of rows to fetch from the query result.
- rows_to_fetch (
-
Returns: (
Dict[str, Any]
) A dictionary-like object containing the response from the server.This function is responsible for fetching additional rows from the query result. It sends a request to the server to fetch more rows, waits for a response, and returns the result.
Query Objects
A query object is a dictionary-like object that represents a SQL query to be executed. It contains the SQL statement, any additional options, and the unique identifier for the query. The query object is used to manage the state of the query, send it to the server, and fetch results.
Here is a sample definition of a query object:
query_object = { "id": self.job._get_unique_id("query"), "type": "prepare_sql_execute" if self.is_prepared else "sql", "sql": self.sql, "terse": self.is_terse_results, "rows": rows_to_fetch, "parameters": self.parameters,}
Here is a sample definition of a query object for a cl command:
query_object = { "id": self.job._get_unique_id("clcommand"), "type": "cl", "terse": self.is_terse_results, "cmd": self.sql,}
here is a sample definition of a query object for fetch more:
query_object = { "id": self.job._get_unique_id("fetchMore"), "cont_id": self._correlation_id, "type": "sqlmore", "sql": self.sql, "rows": rows_to_fetch,}
Example usage in python
creds = DaemonServer( host="localhost", port=8085, user=user, password=pw, ignoreUnauthorized=True,)
job = SQLJob()res = job.connect(creds)query = job.query("select * from sample.employee")result = query.run(rows_to_fetch=5)job.close()