@@ -2682,6 +2682,30 @@ class ColumnInfo(List):
2682
2682
def __init__ (self , driver :SQLDriver , table_name :str ):
2683
2683
self .driver = driver
2684
2684
self .table_name = table_name
2685
+
2686
+ # List of required SQL types to check against when user sets custom values
2687
+ self ._sql_types = [
2688
+ 'TEXT' ,'VARCHAR' , 'CHAR' , 'INTEGER' , 'REAL' , 'DOUBLE' , 'FLOAT' , 'DECIMAL' , 'BOOLEAN' , 'TIME' , 'DATE' ,
2689
+ 'DATETIME' , 'TIMESTAMP'
2690
+ ]
2691
+
2692
+ # Defaults to use for Null values returned from the database. These can be overwritten by the user and support
2693
+ # function calls as well
2694
+ self .null_defaults = {
2695
+ 'TEXT' : 'New Record' ,
2696
+ 'VARCHAR' : 'New Record' ,
2697
+ 'CHAR' : 'New Record' ,
2698
+ 'INTEGER' : 1 ,
2699
+ 'REAL' : 0.0 ,
2700
+ 'DOUBLE' : 0.0 ,
2701
+ 'FLOAT' : 0.0 ,
2702
+ 'DECIMAL' : 0.0 ,
2703
+ 'BOOLEAN' : 0 ,
2704
+ 'TIME' : self .default_time (),
2705
+ 'DATE' : self .default_date (),
2706
+ 'TIMESTAMP' : self .default_datetime (),
2707
+ 'DATETIME' : self .default_datetime ()
2708
+ }
2685
2709
super ().__init__ ()
2686
2710
2687
2711
def __contains__ (self , item ):
@@ -2702,7 +2726,7 @@ def col_name(self,idx):
2702
2726
"""Get the column name located at the specified index in this collection of columns"""
2703
2727
return self [idx ].name
2704
2728
2705
- def looks_like_function (self , s :str ):
2729
+ def looks_like_function (self , s :str ): # TODO: check if something looks like a statement for complex defaults? Regex?
2706
2730
# check if the string is empty
2707
2731
if not s :
2708
2732
return False
@@ -2750,25 +2774,20 @@ def default_dict(self, q_obj:Query):
2750
2774
2751
2775
# The stored default is a literal value, lets try to use it:
2752
2776
if default is None :
2753
- if sql_type == 'BOOLEAN' :
2754
- default = 0
2755
- elif sql_type in ['TEXT' ,'VARCHAR' ,'CHAR' ]:
2756
- if c .name == q_obj .description_column :
2757
- default = 'New record' # If no default is specified, we have to do something
2758
- elif sql_type in ['REAL' ,'DOUBLE' ,'FLOAT' ,'DECIMAL' ]:
2759
- default = 1.0
2760
- elif sql_type == 'DATE' :
2761
- default = date .today ().strftime ("%Y-%m-%d" )
2762
- elif sql_type in ['DATETIME' ,'TIMESTAMP' ]:
2763
- default = datetime .now ().strftime ("%Y-%m-%d %H:%M:%S" )
2764
- elif sql_type == 'TIME' :
2765
- default = datetime .now ().strftime ("%H:%M:%S" )
2766
- elif sql_type == 'INTEGER' :
2767
- if not c .pk : # we don't want to default our primary key!
2768
- default = 1
2777
+ null_default = self .null_defaults [sql_type ]
2778
+
2779
+ # If our default is callable, call it. Otherwise, assign it
2780
+ # Make sure to skip primary keys, and onlu consider text that is in the description column
2781
+ if (sql_type not in ['TEXT' ,'VARCHAR' ,'CHAR' ] and c .name != q_obj .description_column ) and c .pk == False :
2782
+ print (f'Setting default for { c .name } to { null_default } ' )
2783
+ default = null_default () if callable (null_default ) else null_default
2784
+ else :
2785
+ print (f'Did not set default for { c .name } ' )
2769
2786
else :
2770
- # strip quotes from default strings
2771
- default = c .default .strip ('"\' ' ) # strip leading and trailing quotes
2787
+ # Load the default from the database
2788
+ if sql_type in ['TEXT' , 'VARCHAR' , 'CHAR' ]:
2789
+ # strip quotes from default strings as they seem to get passed with some database-stored defaults
2790
+ default = c .default .strip ('"\' ' ) # strip leading and trailing quotes
2772
2791
2773
2792
d [c .name ]= default
2774
2793
if q_obj .transform is not None : q_obj .transform (d , TFORM_DECODE )
@@ -2781,6 +2800,43 @@ def _contains_key_value_pair(self, key, value): #used by __contains__
2781
2800
return True
2782
2801
return False
2783
2802
2803
+ def default_time (self ):
2804
+ return datetime .now ().strftime ("%H:%M:%S" )
2805
+
2806
+ def default_date (self ):
2807
+ return date .today ().strftime ("%Y-%m-%d" )
2808
+
2809
+ def default_datetime (self ):
2810
+ return datetime .now ().strftime ("%Y-%m-%d %H:%M:%S" )
2811
+
2812
+ def set_null_default (self , sql_type :str , value :object ) -> None :
2813
+ """
2814
+ Set a Null default for a single SQL type
2815
+
2816
+ :param sql_type: The SQL type to set the default for ('INTEGER', 'TEXT', 'BOOLEAN', etc.)
2817
+ :param value: The new value to set the SQL type to. This can be a literal or even a callable
2818
+ :return: None
2819
+ """
2820
+ if sql_type not in self ._sql_types :
2821
+ RuntimeError (f'Unsupported SQL Type: { sql_type } . Supported types are: { self ._sql_types } ' )
2822
+
2823
+ self .null_defaults [sql_type ] = value
2824
+
2825
+ def set_null_defaults (self , null_defaults :dict ) -> None :
2826
+ """
2827
+ Set Null defaults for all SQL types
2828
+
2829
+ supported types: 'TEXT','VARCHAR', 'CHAR', 'INTEGER', 'REAL', 'DOUBLE', 'FLOAT', 'DECIMAL', 'BOOLEAN', 'TIME',
2830
+ 'DATE', 'DATETIME', 'TIMESTAMP'
2831
+ :param null_defaults: A dict of SQL types and default values. This can be a literal or even a callable
2832
+ :return: None
2833
+ """
2834
+ # Check if the null_defaults dict has all of the required keys:
2835
+ if not all (key in null_defaults for key in self ._sql_types ):
2836
+ RuntimeError (f'The supplied null_defaults dictionary does not havle all required SQL types. Required: { self ._sql_types } ' )
2837
+
2838
+ self .null_defaults = null_defaults
2839
+
2784
2840
class ResultColumn :
2785
2841
"""
2786
2842
The ResultColumn class is a generic column class. It holds a dict containing the column name, type whether the
@@ -2840,7 +2896,7 @@ def pk(self, value):
2840
2896
self ._column ['pk' ] = value
2841
2897
2842
2898
def get_names (self ):
2843
- return [v for k ,v in self .columns .items () if key == 'name' ]
2899
+ return [v for k ,v in self .columns .items () if k == 'name' ]
2844
2900
2845
2901
class ResultRow :
2846
2902
# The ResulRow class is a generic row class. It holds a dict containing the columns and values of the row, along
0 commit comments