@@ -956,7 +956,7 @@ def insert_record(self, values:dict=None, skip_prompt_save=False) -> None:
956
956
return
957
957
958
958
# 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 )
960
960
961
961
# If the values parameter was passed in, overwrite any values in the dict
962
962
if values is not None :
@@ -2679,6 +2679,16 @@ def selector(key, table, element=sg.LBox, size=None, columns=None, filter=None,
2679
2679
# ----------------------------------------------------------------------------------------------------------------------
2680
2680
2681
2681
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
+ """
2682
2692
def __init__ (self , driver :SQLDriver , table_name :str ):
2683
2693
self .driver = driver
2684
2694
self .table_name = table_name
@@ -2690,7 +2700,7 @@ def __init__(self, driver:SQLDriver, table_name:str):
2690
2700
]
2691
2701
2692
2702
# 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()
2694
2704
self .null_defaults = {
2695
2705
'TEXT' : 'New Record' ,
2696
2706
'VARCHAR' : 'New Record' ,
@@ -2714,57 +2724,40 @@ def __contains__(self, item):
2714
2724
else :
2715
2725
return super ().__contains__ (item )
2716
2726
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
2740
2730
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' )
2745
2734
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
2749
2738
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
2753
2743
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
2756
2748
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
+ """
2759
2752
d = {}
2760
2753
for c in self :
2761
2754
default = c .default
2762
2755
sql_type = c .sql_type
2763
2756
2764
2757
# 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 ):
2766
2759
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?
2768
2761
rows = self .driver .execute (q )
2769
2762
if rows .exception is None :
2770
2763
default = rows .fetchone ()[default ]
@@ -2793,13 +2786,6 @@ def default_dict(self, q_obj:Query):
2793
2786
if q_obj .transform is not None : q_obj .transform (d , TFORM_DECODE )
2794
2787
return d
2795
2788
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
-
2803
2789
def set_null_default (self , sql_type :str , value :object ) -> None :
2804
2790
"""
2805
2791
Set a Null default for a single SQL type
@@ -2828,10 +2814,59 @@ def set_null_defaults(self, null_defaults:dict) -> None:
2828
2814
2829
2815
self .null_defaults = null_defaults
2830
2816
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
+
2831
2855
class ResultColumn :
2832
2856
"""
2833
2857
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
+ ```
2835
2870
"""
2836
2871
def __init__ (self , name :str , sql_type :str , notnull :bool , default :None , pk :bool ):
2837
2872
self ._column = {'name' : name , 'sql_type' : sql_type , 'notnull' : notnull , 'default' : default , 'pk' : pk }
@@ -2886,15 +2921,16 @@ def pk(self):
2886
2921
def pk (self , value ):
2887
2922
self ._column ['pk' ] = value
2888
2923
2889
- def get_names (self ):
2890
- return [v for k ,v in self .columns .items () if k == 'name' ]
2891
2924
2892
2925
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
+
2898
2934
def __init__ (self , row :dict , virtual = False ):
2899
2935
self .row = row
2900
2936
self .virtual = virtual
0 commit comments