@@ -78,7 +78,7 @@ def optimize(self):
78
78
table .cleanup_metadata ()
79
79
table .create_checkpoint ()
80
80
81
- def getPartitions (self ) -> Dict [str , List [Any ]] | None :
81
+ def getPartitions (self ) -> Optional [ Dict [str , List [Any ]]] :
82
82
table = self .getConn ()
83
83
84
84
partitions : Dict [str , List [Any ]] = {}
@@ -91,11 +91,11 @@ def getPartitions(self) -> Dict[str, List[Any]] | None:
91
91
92
92
return partitions
93
93
94
- def getCurrentVersion (self ) -> str | None :
94
+ def getCurrentVersion (self ) -> Optional [ str ] :
95
95
table = self .getConn ()
96
96
return str (table .get_version ())
97
97
98
- def getVersions (self ) -> List [str ] | None :
98
+ def getVersions (self ) -> Optional [ List [str ]] :
99
99
return [str (self .getCurrentVersion ())]
100
100
101
101
def insert (self , data : List [Any ]) -> bool :
@@ -108,10 +108,29 @@ def insert(self, data: List[Any]) -> bool:
108
108
)
109
109
return True
110
110
111
+ def _escape_value (self , val : Any ) -> str :
112
+ """Properly escape values for predicate building to prevent injection issues."""
113
+ if isinstance (val , str ):
114
+ # Escape single quotes in strings and wrap in quotes
115
+ return f"'{ val .replace (\" '\" , \" ' '\" )} "
116
+ elif isinstance (val , (int , float )):
117
+ return str (val )
118
+ elif isinstance (val , bool ):
119
+ return str (val ).lower ()
120
+ elif val is None :
121
+ return "null"
122
+ elif isinstance (val , list ):
123
+ # Handle list values for 'in' operations
124
+ escaped_items = [self ._escape_value (item ) for item in val ]
125
+ return f"({ ', ' .join (escaped_items )} )"
126
+ else :
127
+ # Fallback to string representation with quotes
128
+ return f"'{ str (val ).replace (\" '\" , \" ' '\" )} "
129
+
111
130
def _filters (
112
131
self ,
113
- partitions : Dict [str , List [Any ]] | None = None ,
114
- ) -> List [Tuple [str , str , Any ]] | None :
132
+ partitions : Optional [ Dict [str , List [Any ]]] = None ,
133
+ ) -> Optional [ List [Tuple [str , str , Any ]]] :
115
134
filters : List [Tuple [str , str , Any ]] = []
116
135
if partitions is None :
117
136
return None
@@ -123,14 +142,14 @@ def _filters(
123
142
return filters if len (filters ) > 0 else None
124
143
125
144
def overwrite (
126
- self , data : List [Any ], partitions : Dict [str , List [Any ]] | None = None
145
+ self , data : List [Any ], partitions : Optional [ Dict [str , List [Any ]]] = None
127
146
) -> bool :
128
147
table = self .getConn ()
129
148
130
- predicate : str | None = None
149
+ predicate : Optional [ str ] = None
131
150
filter = self ._filters (partitions )
132
151
if filter is not None :
133
- predicate = " & " .join ([f"{ col } { op } { str (val )} " for col , op , val in filter ])
152
+ predicate = " & " .join ([f"{ col } { op } { self . _escape_value (val )} " for col , op , val in filter ])
134
153
135
154
write_deltalake (
136
155
table ,
@@ -144,9 +163,9 @@ def overwrite(
144
163
def readRaw (
145
164
self ,
146
165
columns : List [str ],
147
- partitions : Dict [str , List [Any ]] | None = None ,
148
- version : str | None = None ,
149
- options : Any | None = None ,
166
+ partitions : Optional [ Dict [str , List [Any ]]] = None ,
167
+ version : Optional [ str ] = None ,
168
+ options : Optional [ Any ] = None ,
150
169
) -> Table :
151
170
table = self .getConn ()
152
171
if version is not None :
@@ -172,13 +191,13 @@ def readRaw(
172
191
def read (
173
192
self ,
174
193
columns : List [str ],
175
- partitions : Dict [str , List [Any ]] | None = None ,
176
- version : str | None = None ,
177
- options : Any | None = None ,
194
+ partitions : Optional [ Dict [str , List [Any ]]] = None ,
195
+ version : Optional [ str ] = None ,
196
+ options : Optional [ Any ] = None ,
178
197
) -> Table :
179
198
return self .readRaw (columns , partitions , version , options )
180
199
181
- def getSchema (self ) -> Schema | None :
200
+ def getSchema (self ) -> Optional [ Schema ] :
182
201
table = self .getConn ()
183
202
184
203
return table .schema .to_pyarrow ()
0 commit comments