Skip to content

Commit 7320dfc

Browse files
committed
refs #74
Cleaning up and documentation improvements
1 parent f66ec47 commit 7320dfc

File tree

1 file changed

+92
-56
lines changed

1 file changed

+92
-56
lines changed

pysimplesql/pysimplesql.py

+92-56
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,7 @@ def insert_record(self, values:dict=None, skip_prompt_save=False) -> None:
956956
return
957957

958958
# Get a new dict for a new row with default values already filled in
959-
new_values = self.column_info.default_dict(self)
959+
new_values = self.column_info.default_row_dict(self)
960960

961961
# If the values parameter was passed in, overwrite any values in the dict
962962
if values is not None:
@@ -2679,6 +2679,16 @@ def selector(key, table, element=sg.LBox, size=None, columns=None, filter=None,
26792679
# ----------------------------------------------------------------------------------------------------------------------
26802680

26812681
class ColumnInfo(List):
2682+
"""
2683+
Column Information Class
2684+
2685+
The ColumnInfo class is a custom container that behaves like a List containing a collection of ResultColumns. This
2686+
class is responsible for maintaining information about all of the columns (ResultColumn) in a table. While the
2687+
individual ResultColumn elements of this collection contain information such as default values, primary key status,
2688+
SQL data type, column name, and the notnull status - this class ties them all together into a collection and adds
2689+
functionality to set default values for null columns and retrieve a dict representing a table row with all defaults
2690+
already assigned.
2691+
"""
26822692
def __init__(self, driver:SQLDriver, table_name:str):
26832693
self.driver = driver
26842694
self.table_name = table_name
@@ -2690,7 +2700,7 @@ def __init__(self, driver:SQLDriver, table_name:str):
26902700
]
26912701

26922702
# Defaults to use for Null values returned from the database. These can be overwritten by the user and support
2693-
# function calls as well
2703+
# function calls as well by using ColumnInfo.set_null_default() and ColumnInfo.set_null_defaults()
26942704
self.null_defaults = {
26952705
'TEXT': 'New Record',
26962706
'VARCHAR': 'New Record',
@@ -2714,57 +2724,40 @@ def __contains__(self, item):
27142724
else:
27152725
return super().__contains__(item)
27162726

2717-
def getlist(self, key:str) -> List:
2718-
"""returns a list of any key in the underlying ResultColumn instances. For example, column names, types, defaults, etc."""
2719-
return [d[key] for d in self]
2720-
2721-
def names(self):
2722-
"""Return a List of column names from this collection"""
2723-
return self.getlist('name')
2724-
2725-
def col_name(self,idx):
2726-
"""Get the column name located at the specified index in this collection of columns"""
2727-
return self[idx].name
2728-
2729-
def looks_like_function(self, s:str): # TODO: check if something looks like a statement for complex defaults? Regex?
2730-
# check if the string is empty
2731-
if not s:
2732-
return False
2733-
2734-
# find the index of the first opening parenthesis
2735-
open_paren_index = s.find("(")
2736-
2737-
# if there is no opening parenthesis, the string is not a function
2738-
if open_paren_index == -1:
2739-
return False
2727+
def names(self) -> List:
2728+
"""
2729+
Return a List of column names from the ResultColumns in this collection
27402730
2741-
# check if there is a name before the opening parenthesis
2742-
name = s[:open_paren_index].strip()
2743-
if not name.isidentifier():
2744-
return False
2731+
:return: List
2732+
"""
2733+
return self._get_list('name')
27452734

2746-
# find the index of the last closing parenthesis
2747-
last_char_index = len(s) - 1
2748-
close_paren_index = s.rfind(")")
2735+
def col_name(self,idx:int) -> str:
2736+
"""
2737+
Get the column name located at the specified index in this collection of ResultColumns
27492738
2750-
# if there is no closing parenthesis, the string is not a function
2751-
if close_paren_index == -1 or close_paren_index <= open_paren_index:
2752-
return False
2739+
:param idx: The index of the column to get the name from
2740+
:return: The name of the column at the specified index
2741+
"""
2742+
return self[idx].name
27532743

2754-
# if all checks pass, the string looks like a function
2755-
return True
2744+
def default_row_dict(self, q_obj:Query) -> dict:
2745+
"""
2746+
Return a dictionary of a table row with all defaults assigned. This is useful for inserting new records to
2747+
prefill the GUI elements
27562748
2757-
def default_dict(self, q_obj:Query):
2758-
"""Return a dict of name: default value pairs"""
2749+
:param q_obj: a pysimplesql Query object
2750+
:return: dict
2751+
"""
27592752
d = {}
27602753
for c in self:
27612754
default = c.default
27622755
sql_type = c.sql_type
27632756

27642757
# First, check to see if the default might be a database function
2765-
if self.looks_like_function(default):
2758+
if self._looks_like_function(default):
27662759
table_name = self.driver.quote_table(self.table_name)
2767-
q = f'SELECT {default} FROM {table_name};' # TODO: may need as column_name to support all databases?
2760+
q = f'SELECT {default} FROM {table_name};' # TODO: may need AS column_name to support all databases?
27682761
rows = self.driver.execute(q)
27692762
if rows.exception is None:
27702763
default = rows.fetchone()[default]
@@ -2793,13 +2786,6 @@ def default_dict(self, q_obj:Query):
27932786
if q_obj.transform is not None: q_obj.transform(d, TFORM_DECODE)
27942787
return d
27952788

2796-
2797-
def _contains_key_value_pair(self, key, value): #used by __contains__
2798-
for d in self:
2799-
if key in d and d[key] == value:
2800-
return True
2801-
return False
2802-
28032789
def set_null_default(self, sql_type:str, value:object) -> None:
28042790
"""
28052791
Set a Null default for a single SQL type
@@ -2828,10 +2814,59 @@ def set_null_defaults(self, null_defaults:dict) -> None:
28282814

28292815
self.null_defaults = null_defaults
28302816

2817+
def _contains_key_value_pair(self, key, value): #used by __contains__
2818+
for d in self:
2819+
if key in d and d[key] == value:
2820+
return True
2821+
return False
2822+
2823+
def _looks_like_function(self, s:str): # TODO: check if something looks like a statement for complex defaults? Regex?
2824+
# check if the string is empty
2825+
if not s:
2826+
return False
2827+
2828+
# find the index of the first opening parenthesis
2829+
open_paren_index = s.find("(")
2830+
2831+
# if there is no opening parenthesis, the string is not a function
2832+
if open_paren_index == -1:
2833+
return False
2834+
2835+
# check if there is a name before the opening parenthesis
2836+
name = s[:open_paren_index].strip()
2837+
if not name.isidentifier():
2838+
return False
2839+
2840+
# find the index of the last closing parenthesis
2841+
last_char_index = len(s) - 1
2842+
close_paren_index = s.rfind(")")
2843+
2844+
# if there is no closing parenthesis, the string is not a function
2845+
if close_paren_index == -1 or close_paren_index <= open_paren_index:
2846+
return False
2847+
2848+
# if all checks pass, the string looks like a function
2849+
return True
2850+
2851+
def _get_list(self, key: str) -> List:
2852+
# returns a list of any key in the underlying ResultColumn instances. For example, column names, types, defaults, etc.
2853+
return [d[key] for d in self]
2854+
28312855
class ResultColumn:
28322856
"""
28332857
The ResultColumn class is a generic column class. It holds a dict containing the column name, type whether the
2834-
column is nullable and the default value, if any
2858+
column is notnull, whether the column is a primary key and the default value, if any. ResultColumns are typically
2859+
stored in a ColumnInfo collection. There are multiple ways to get information from a ResultColumn, including subscript
2860+
notation, and via properties. The available column info via these methods are name, sql_type, notnull, default and pk
2861+
See example:
2862+
```python
2863+
# Get the of the first column selecting a ResultColumn from the stored ColumnInfo collection
2864+
col_name = frm['Journal'].column_info[0]['name'] # uses subscript notation
2865+
col_name = frm['Journal'].column_info[0].name # uses the name property
2866+
2867+
# Get the default value stored in the database for the 'title' column
2868+
default = frm['Journal'].column_info['title'].default
2869+
```
28352870
"""
28362871
def __init__(self, name:str, sql_type:str, notnull:bool, default:None, pk:bool):
28372872
self._column={'name': name, 'sql_type': sql_type, 'notnull': notnull, 'default': default, 'pk': pk}
@@ -2886,15 +2921,16 @@ def pk(self):
28862921
def pk(self, value):
28872922
self._column['pk'] = value
28882923

2889-
def get_names(self):
2890-
return [v for k,v in self.columns.items() if k == 'name']
28912924

28922925
class ResultRow:
2893-
# The ResulRow class is a generic row class. It holds a dict containing the columns and values of the row, along
2894-
# with a "virtual" flag. A "virtual" row is one which exists in PySimpleSQL, but not in the underlying database.
2895-
# This is useful for inserting records or other temporary storage of records. Note that when querying a database,
2896-
# the virtual flag will never be set - it is only set by the end user by calling <ResultSet>.insert() to insert a
2897-
# new virtual row.
2926+
"""
2927+
The ResulRow class is a generic row class. It holds a dict containing the columns and values of the row, along
2928+
with a "virtual" flag. A "virtual" row is one which exists in PySimpleSQL, but not in the underlying database.
2929+
This is useful for inserting records or other temporary storage of records. Note that when querying a database,
2930+
the virtual flag will never be set - it is only set by the end user by calling <ResultSet>.insert() to insert a
2931+
new virtual row.
2932+
"""
2933+
28982934
def __init__(self, row:dict, virtual=False):
28992935
self.row = row
29002936
self.virtual=virtual

0 commit comments

Comments
 (0)