From 8a35c1c585b1e60ca99230fbfd194922f55f6d8e Mon Sep 17 00:00:00 2001 From: amochin Date: Mon, 20 Nov 2023 18:58:15 +0100 Subject: [PATCH 1/4] Bump version to 1.4.1 --- src/DatabaseLibrary/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DatabaseLibrary/version.py b/src/DatabaseLibrary/version.py index 5d4d63c..bababb5 100644 --- a/src/DatabaseLibrary/version.py +++ b/src/DatabaseLibrary/version.py @@ -1 +1 @@ -VERSION = "1.4" +VERSION = "1.4.1" From a212ff0fd08c70abda9a15fdd19a46b55097124a Mon Sep 17 00:00:00 2001 From: amochin Date: Mon, 20 Nov 2023 19:07:11 +0100 Subject: [PATCH 2/4] Forgot new query params in some keyword docs --- src/DatabaseLibrary/assertion.py | 31 +++++++- src/DatabaseLibrary/query.py | 119 +++++++++++++++---------------- 2 files changed, 86 insertions(+), 64 deletions(-) diff --git a/src/DatabaseLibrary/assertion.py b/src/DatabaseLibrary/assertion.py index 7e0862f..c3ecb87 100644 --- a/src/DatabaseLibrary/assertion.py +++ b/src/DatabaseLibrary/assertion.py @@ -41,11 +41,16 @@ def check_if_exists_in_database( Use optional ``alias`` parameter to specify what connection should be used for the query if you have more than one connection open. + Use optional ``parameters`` for query variable substitution (variable substitution syntax may be different + depending on the database client). + Examples: | Check If Exists In Database | SELECT id FROM person WHERE first_name = 'Franz Allan' | | Check If Exists In Database | SELECT id FROM person WHERE first_name = 'John' | msg=my error message | | Check If Exists In Database | SELECT id FROM person WHERE first_name = 'Franz Allan' | alias=my_alias | | Check If Exists In Database | SELECT id FROM person WHERE first_name = 'John' | sansTran=True | + | @{parameters} | Create List | John | + | Check If Exists In Database | SELECT id FROM person WHERE first_name = %s | parameters=${parameters} | """ logger.info(f"Executing : Check If Exists In Database | {selectStatement}") if not self.query(selectStatement, sansTran, alias=alias, parameters=parameters): @@ -74,11 +79,16 @@ def check_if_not_exists_in_database( Use optional ``alias`` parameter to specify what connection should be used for the query if you have more than one connection open. + Use optional ``parameters`` for query variable substitution (variable substitution syntax may be different + depending on the database client). + Examples: | Check If Not Exists In Database | SELECT id FROM person WHERE first_name = 'John' | | Check If Not Exists In Database | SELECT id FROM person WHERE first_name = 'Franz Allan' | msg=my error message | | Check If Not Exists In Database | SELECT id FROM person WHERE first_name = 'Franz Allan' | alias=my_alias | | Check If Not Exists In Database | SELECT id FROM person WHERE first_name = 'John' | sansTran=True | + | @{parameters} | Create List | John | + | Check If Not Exists In Database | SELECT id FROM person WHERE first_name = %s | parameters=${parameters} | """ logger.info(f"Executing : Check If Not Exists In Database | {selectStatement}") query_results = self.query(selectStatement, sansTran, alias=alias, parameters=parameters) @@ -107,11 +117,16 @@ def row_count_is_0( Use optional ``alias`` parameter to specify what connection should be used for the query if you have more than one connection open. + Use optional ``parameters`` for query variable substitution (variable substitution syntax may be different + depending on the database client). + Examples: | Row Count is 0 | SELECT id FROM person WHERE first_name = 'Franz Allan' | | Row Count is 0 | SELECT id FROM person WHERE first_name = 'Franz Allan' | msg=my error message | | Row Count is 0 | SELECT id FROM person WHERE first_name = 'John' | alias=my_alias | | Row Count is 0 | SELECT id FROM person WHERE first_name = 'John' | sansTran=True | + | @{parameters} | Create List | John | + | Row Count is 0 | SELECT id FROM person WHERE first_name = %s | parameters=${parameters} | """ logger.info(f"Executing : Row Count Is 0 | {selectStatement}") num_rows = self.row_count(selectStatement, sansTran, alias=alias, parameters=parameters) @@ -138,11 +153,16 @@ def row_count_is_equal_to_x( Use optional ``alias`` parameter to specify what connection should be used for the query if you have more than one connection open. + Use optional ``parameters`` for query variable substitution (variable substitution syntax may be different + depending on the database client). + Examples: | Row Count Is Equal To X | SELECT id FROM person | 1 | | Row Count Is Equal To X | SELECT id FROM person | 3 | msg=my error message | | Row Count Is Equal To X | SELECT id FROM person WHERE first_name = 'John' | 0 | alias=my_alias | | Row Count Is Equal To X | SELECT id FROM person WHERE first_name = 'John' | 0 | sansTran=True | + | @{parameters} | Create List | John | + | Row Count Is Equal To X | SELECT id FROM person WHERE first_name = %s | 0 | parameters=${parameters} | """ logger.info(f"Executing : Row Count Is Equal To X | {selectStatement} | {numRows}") num_rows = self.row_count(selectStatement, sansTran, alias=alias, parameters=parameters) @@ -171,11 +191,16 @@ def row_count_is_greater_than_x( Use optional ``alias`` parameter to specify what connection should be used for the query if you have more than one connection open. + Use optional ``parameters`` for query variable substitution (variable substitution syntax may be different + depending on the database client). + Examples: | Row Count Is Greater Than X | SELECT id FROM person WHERE first_name = 'John' | 0 | | Row Count Is Greater Than X | SELECT id FROM person WHERE first_name = 'John' | 0 | msg=my error message | | Row Count Is Greater Than X | SELECT id FROM person WHERE first_name = 'John' | 0 | alias=my_alias | | Row Count Is Greater Than X | SELECT id FROM person | 1 | sansTran=True | + | @{parameters} | Create List | John | + | Row Count Is Greater Than X | SELECT id FROM person WHERE first_name = %s | 0 | parameters=${parameters} | """ logger.info(f"Executing : Row Count Is Greater Than X | {selectStatement} | {numRows}") num_rows = self.row_count(selectStatement, sansTran, alias=alias, parameters=parameters) @@ -204,12 +229,16 @@ def row_count_is_less_than_x( Use optional ``alias`` parameter to specify what connection should be used for the query if you have more than one connection open. + Use optional ``parameters`` for query variable substitution (variable substitution syntax may be different + depending on the database client). + Examples: | Row Count Is Less Than X | SELECT id FROM person WHERE first_name = 'John' | 1 | | Row Count Is Less Than X | SELECT id FROM person WHERE first_name = 'John' | 2 | msg=my error message | | Row Count Is Less Than X | SELECT id FROM person WHERE first_name = 'John' | 3 | alias=my_alias | | Row Count Is Less Than X | SELECT id FROM person WHERE first_name = 'John' | 4 | sansTran=True | - + | @{parameters} | Create List | John | + | Row Count Is Less Than X | SELECT id FROM person WHERE first_name = %s | 5 | parameters=${parameters} | """ logger.info(f"Executing : Row Count Is Less Than X | {selectStatement} | {numRows}") num_rows = self.row_count(selectStatement, sansTran, alias=alias, parameters=parameters) diff --git a/src/DatabaseLibrary/query.py b/src/DatabaseLibrary/query.py index 01a4842..2be123f 100644 --- a/src/DatabaseLibrary/query.py +++ b/src/DatabaseLibrary/query.py @@ -25,7 +25,12 @@ class Query: """ def query( - self, selectStatement: str, sansTran: bool = False, returnAsDict: bool = False, alias: Optional[str] = None, parameters: Optional[List] = None + self, + selectStatement: str, + sansTran: bool = False, + returnAsDict: bool = False, + alias: Optional[str] = None, + parameters: Optional[List] = None, ): """ Uses the input ``selectStatement`` to query for the values that will be returned as a list of tuples. @@ -34,6 +39,14 @@ def query( Use optional ``alias`` parameter to specify what connection should be used for the query if you have more than one connection open. + Use optional ``parameters`` for query variable substitution (variable substitution syntax may be different + depending on the database client): + | @{parameters} | Create List | person | + | Query | SELECT * FROM %s | parameters=${parameters} | + + Use optional ``sansTran`` to run command without an explicit transaction commit or rollback: + | @{queryResults} | Query | SELECT * FROM person | True | + Tip: Unless you want to log all column values of the specified rows, try specifying the column names in your select statements as much as possible to prevent any unnecessary surprises with schema @@ -59,14 +72,6 @@ def query( And get the following See, Franz Allan - - Use optional ``parameters`` for query variable substitution (variable substitution syntax may be different - depending on the database client): - | parameters | Create List | person | - | Query | SELECT * FROM %s | parameters=${parameters} | - - Use optional ``sansTran`` to run command without an explicit transaction commit or rollback: - | @{queryResults} | Query | SELECT * FROM person | True | """ db_connection = self.connection_store.get_connection(alias) cur = None @@ -83,40 +88,30 @@ def query( if cur and not sansTran: db_connection.client.rollback() - def row_count(self, selectStatement: str, sansTran: bool = False, alias: Optional[str] = None, parameters: Optional[List] = None): + def row_count( + self, + selectStatement: str, + sansTran: bool = False, + alias: Optional[str] = None, + parameters: Optional[List] = None, + ): """ Uses the input ``selectStatement`` to query the database and returns the number of rows from the query. - For example, given we have a table `person` with the following data: - | id | first_name | last_name | - | 1 | Franz Allan | See | - | 2 | Jerry | Schneider | - - When you do the following: - | ${rowCount} | Row Count | SELECT * FROM person | - | ${rowCount} | Row Count | SELECT * FROM person | alias=my_alias | - | Log | ${rowCount} | - - You will get the following: - 2 - - Also, you can do something like this: - | ${rowCount} | Row Count | SELECT * FROM person WHERE id = 2 | - | Log | ${rowCount} | - - And get the following - 1 - Use optional ``alias`` parameter to specify what connection should be used for the query if you have more than one connection open. + Use optional ``sansTran`` to run command without an explicit transaction commit or rollback: + Use optional ``parameters`` for query variable substitution (variable substitution syntax may be different depending on the database client): - | parameters | Create List | person | - | ${rowCount} | Row Count | SELECT * FROM %s | parameters=${parameters} | - Use optional ``sansTran`` to run command without an explicit transaction commit or rollback: - | ${rowCount} | Row Count | SELECT * FROM person | True | + Examples: + | ${rowCount} | Row Count | SELECT * FROM person | + | ${rowCount} | Row Count | SELECT * FROM person | sansTran=True | + | ${rowCount} | Row Count | SELECT * FROM person | alias=my_alias | + | @{parameters} | Create List | person | + | ${rowCount} | Row Count | SELECT * FROM %s | parameters=${parameters} | """ db_connection = self.connection_store.get_connection(alias) cur = None @@ -132,7 +127,13 @@ def row_count(self, selectStatement: str, sansTran: bool = False, alias: Optiona if cur and not sansTran: db_connection.client.rollback() - def description(self, selectStatement: str, sansTran: bool = False, alias: Optional[str] = None, parameters: Optional[List] = None): + def description( + self, + selectStatement: str, + sansTran: bool = False, + alias: Optional[str] = None, + parameters: Optional[List] = None, + ): """ Uses the input ``selectStatement`` to query a table in the db which will be used to determine the description. @@ -155,7 +156,7 @@ def description(self, selectStatement: str, sansTran: bool = False, alias: Optio Use optional ``parameters`` for query variable substitution (variable substitution syntax may be different depending on the database client): - | parameters | Create List | person | + | @{parameters} | Create List | person | | ${desc} | Description | SELECT * FROM %s | parameters=${parameters} | Using optional `sansTran` to run command without an explicit transaction commit or rollback: @@ -180,23 +181,15 @@ def delete_all_rows_from_table(self, tableName: str, sansTran: bool = False, ali """ Delete all the rows within a given table. - For example, given we have a table `person` in a database - - When you do the following: - | Delete All Rows From Table | person | - | Delete All Rows From Table | person | alias=my_alias | - - If all the rows can be successfully deleted, then you will get: - | Delete All Rows From Table | person | # PASS | - If the table doesn't exist or all the data can't be deleted, then you - will get: - | Delete All Rows From Table | first_name | # FAIL | + Use optional `sansTran` to run command without an explicit transaction commit or rollback. Use optional ``alias`` parameter to specify what connection should be used for the query if you have more than one connection open. - Use optional `sansTran` to run command without an explicit transaction commit or rollback: - | Delete All Rows From Table | person | True | + Examples: + | Delete All Rows From Table | person | + | Delete All Rows From Table | person | alias=my_alias | + | Delete All Rows From Table | person | sansTran=True | """ db_connection = self.connection_store.get_connection(alias) cur = None @@ -341,29 +334,27 @@ def execute_sql_script(self, sqlScriptFileName: str, sansTran: bool = False, ali if cur and not sansTran: db_connection.client.rollback() - def execute_sql_string(self, sqlString: str, sansTran: bool = False, alias: Optional[str] = None, parameters: Optional[List] = None): + def execute_sql_string( + self, sqlString: str, sansTran: bool = False, alias: Optional[str] = None, parameters: Optional[List] = None + ): """ Executes the sqlString as SQL commands. Useful to pass arguments to your sql. - SQL commands are expected to be delimited by a semicolon (';'). - For example: - | Execute Sql String | DELETE FROM person_employee_table; DELETE FROM person_table | - | Execute Sql String | DELETE FROM person_employee_table; DELETE FROM person_table | alias=my_alias | - - For example with an argument: - | Execute Sql String | SELECT * FROM person WHERE first_name = ${FIRSTNAME} | + Use optional `sansTran` to run command without an explicit transaction commit or rollback: Use optional ``alias`` parameter to specify what connection should be used for the query if you have more than one connection open. Use optional ``parameters`` for query variable substitution (variable substitution syntax may be different - depending on the database client): - | parameters | Create List | person_employee_table | - | Execute Sql String | SELECT * FROM %s | parameters=${parameters} | + depending on the database client). - Use optional `sansTran` to run command without an explicit transaction commit or rollback: - | Execute Sql String | DELETE FROM person_employee_table; DELETE FROM person_table | True | + For example: + | Execute Sql String | DELETE FROM person_employee_table; DELETE FROM person_table | + | Execute Sql String | DELETE FROM person_employee_table; DELETE FROM person_table | alias=my_alias | + | Execute Sql String | DELETE FROM person_employee_table; DELETE FROM person_table | sansTran=True | + | @{parameters} | Create List | person_employee_table | + | Execute Sql String | SELECT * FROM %s | parameters=${parameters} | """ db_connection = self.connection_store.get_connection(alias) cur = None @@ -519,7 +510,9 @@ def call_stored_procedure( if cur and not sansTran: db_connection.client.rollback() - def __execute_sql(self, cur, sql_statement: str, omit_trailing_semicolon: Optional[bool] = None, parameters: Optional[List] = None): + def __execute_sql( + self, cur, sql_statement: str, omit_trailing_semicolon: Optional[bool] = None, parameters: Optional[List] = None + ): """ Runs the `sql_statement` using `cur` as Cursor object. Use `omit_trailing_semicolon` parameter (bool) for explicit instruction, From 5ba748578cd46c56215df4bc7d59d6b195a3112b Mon Sep 17 00:00:00 2001 From: amochin Date: Mon, 20 Nov 2023 19:10:47 +0100 Subject: [PATCH 3/4] Update main docs in the lib source code --- src/DatabaseLibrary/__init__.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/DatabaseLibrary/__init__.py b/src/DatabaseLibrary/__init__.py index cd70e0b..1bf24f0 100644 --- a/src/DatabaseLibrary/__init__.py +++ b/src/DatabaseLibrary/__init__.py @@ -37,7 +37,7 @@ class DatabaseLibrary(ConnectionManager, Query, Assertion): Don't forget to install the required Python database module! == Usage example == - + === Basic usage === | *** Settings *** | Library DatabaseLibrary | Test Setup Connect To My Oracle DB @@ -65,6 +65,30 @@ class DatabaseLibrary(ConnectionManager, Query, Assertion): | Check If Not Exists In Database ${sql} | + === Handling multiple database connections === + | *** Settings *** + | Library DatabaseLibrary + | Test Setup Connect To All Databases + | Test Teardown Disconnect From All Databases + | + | *** Keywords *** + | Connect To All Databases + | Connect To Database psycopg2 db db_user pass 127.0.0.1 5432 + | ... alias=postgres + | Connect To Database pymysql db db_user pass 127.0.0.1 3306 + | ... alias=mysql + | + | *** Test Cases *** + | Using Aliases + | ${names}= Query select LAST_NAME from person alias=postgres + | Execute Sql String drop table XYZ alias=mysql + | + | Switching Default Alias + | Switch Database postgres + | ${names}= Query select LAST_NAME from person + | Switch Database mysql + | Execute Sql String drop table XYZ + | == Database modules compatibility == The library is basically compatible with any [https://peps.python.org/pep-0249|Python Database API Specification 2.0] module. From 7b0ddde10fe2d58e3bef16a285d872658a0e628e Mon Sep 17 00:00:00 2001 From: amochin Date: Mon, 20 Nov 2023 19:11:07 +0100 Subject: [PATCH 4/4] Update keyword docs --- doc/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/index.html b/doc/index.html index 6c6c8a6..baf9a8e 100644 --- a/doc/index.html +++ b/doc/index.html @@ -1180,7 +1180,7 @@ jQuery.extend({highlight:function(e,t,n,r){if(e.nodeType===3){var i=e.data.match(t);if(i){var s=document.createElement(n||"span");s.className=r||"highlight";var o=e.splitText(i.index);o.splitText(i[0].length);var u=o.cloneNode(true);s.appendChild(u);o.parentNode.replaceChild(s,o);return 1}}else if(e.nodeType===1&&e.childNodes&&!/(script|style)/i.test(e.tagName)&&!(e.tagName===n.toUpperCase()&&e.className===r)){for(var a=0;a