@@ -114,255 +114,39 @@ impl ToHoverMarkdown for Table {
114114}
115115
116116fn extract_basic_default_literal ( default_expr : & str ) -> Option < String > {
117- let mut candidate = default_expr. trim ( ) ;
117+ let mut cast_parts = default_expr. split ( "::" ) ;
118+ let mut value = cast_parts. next ( ) . unwrap_or ( default_expr) . trim ( ) ;
118119
119- loop {
120- let mut changed = false ;
121-
122- if let Some ( unwrapped) = strip_outer_parentheses ( candidate) {
123- candidate = unwrapped. trim ( ) ;
124- changed = true ;
125- }
126-
127- if let Some ( without_cast) = strip_trailing_top_level_casts ( candidate) {
128- candidate = without_cast. trim ( ) ;
129- changed = true ;
130- }
131-
132- if !changed {
133- break ;
134- }
135- }
136-
137- if is_basic_literal ( candidate) {
138- Some ( candidate. to_string ( ) )
139- } else {
140- None
141- }
142- }
143-
144- fn strip_outer_parentheses ( value : & str ) -> Option < & str > {
145- let value = value. trim ( ) ;
146-
147- if !value. starts_with ( '(' ) || !value. ends_with ( ')' ) {
120+ if cast_parts. any ( |cast_part| !is_type_cast_fragment ( cast_part) ) {
148121 return None ;
149122 }
150123
151- let mut depth = 0_i32 ;
152- let mut in_single_quote = false ;
153- let mut in_double_quote = false ;
154- let bytes = value. as_bytes ( ) ;
155- let mut idx = 0_usize ;
156-
157- while idx < bytes. len ( ) {
158- let ch = bytes[ idx] as char ;
159-
160- if in_single_quote {
161- if ch == '\'' {
162- if idx + 1 < bytes. len ( ) && bytes[ idx + 1 ] as char == '\'' {
163- idx += 2 ;
164- continue ;
165- }
166-
167- in_single_quote = false ;
168- }
169-
170- idx += 1 ;
171- continue ;
172- }
173-
174- if in_double_quote {
175- if ch == '"' {
176- in_double_quote = false ;
177- }
178-
179- idx += 1 ;
180- continue ;
181- }
182-
183- match ch {
184- '\'' => in_single_quote = true ,
185- '"' => in_double_quote = true ,
186- '(' => depth += 1 ,
187- ')' => {
188- depth -= 1 ;
189- if depth == 0 && idx != bytes. len ( ) - 1 {
190- return None ;
191- }
192- }
193- _ => { }
194- }
195-
196- idx += 1 ;
124+ while value. starts_with ( '(' ) && value. ends_with ( ')' ) && value. len ( ) > 1 {
125+ value = value[ 1 ..value. len ( ) - 1 ] . trim ( ) ;
197126 }
198127
199- if depth != 0 || in_single_quote || in_double_quote {
200- return None ;
128+ if value . starts_with ( '\'' ) && value . ends_with ( '\'' ) && value . len ( ) > 1 {
129+ value = & value [ 1 ..value . len ( ) - 1 ] ;
201130 }
202131
203- Some ( & value[ 1 ..value. len ( ) - 1 ] )
204- }
205-
206- fn strip_trailing_top_level_casts ( value : & str ) -> Option < & str > {
207- let bytes = value. as_bytes ( ) ;
208- let mut depth = 0_i32 ;
209- let mut in_single_quote = false ;
210- let mut in_double_quote = false ;
211- let mut idx = 0_usize ;
212-
213- while idx + 1 < bytes. len ( ) {
214- let ch = bytes[ idx] as char ;
215-
216- if in_single_quote {
217- if ch == '\'' {
218- if idx + 1 < bytes. len ( ) && bytes[ idx + 1 ] as char == '\'' {
219- idx += 2 ;
220- continue ;
221- }
222- in_single_quote = false ;
223- }
224- idx += 1 ;
225- continue ;
226- }
227-
228- if in_double_quote {
229- if ch == '"' {
230- in_double_quote = false ;
231- }
232- idx += 1 ;
233- continue ;
234- }
235-
236- match ch {
237- '\'' => {
238- in_single_quote = true ;
239- idx += 1 ;
240- continue ;
241- }
242- '"' => {
243- in_double_quote = true ;
244- idx += 1 ;
245- continue ;
246- }
247- '(' => {
248- depth += 1 ;
249- idx += 1 ;
250- continue ;
251- }
252- ')' => {
253- depth -= 1 ;
254- idx += 1 ;
255- continue ;
256- }
257- ':' if depth == 0 && bytes[ idx + 1 ] as char == ':' => {
258- let suffix = & value[ idx..] ;
259- if suffix
260- . chars ( )
261- . all ( |c| c. is_ascii_alphanumeric ( ) || ":_\" .()[] ,\t " . contains ( c) )
262- {
263- return Some ( value[ ..idx] . trim_end ( ) ) ;
264- }
265- return None ;
266- }
267- _ => {
268- idx += 1 ;
269- continue ;
270- }
271- }
272- }
273-
274- None
275- }
276-
277- fn is_basic_literal ( value : & str ) -> bool {
278132 let value = value. trim ( ) ;
279-
280- if value. eq_ignore_ascii_case ( "true" )
281- || value. eq_ignore_ascii_case ( "false" )
282- || value. eq_ignore_ascii_case ( "null" )
283- {
284- return true ;
133+ if value. is_empty ( ) || !contains_only_basic_chars ( value) {
134+ return None ;
285135 }
286136
287- is_numeric_literal ( value) || is_single_quoted_literal ( value )
137+ Some ( value. to_string ( ) )
288138}
289139
290- fn is_single_quoted_literal ( value : & str ) -> bool {
291- let bytes = value. as_bytes ( ) ;
292-
293- if bytes. len ( ) < 2 || bytes. first ( ) != Some ( & b'\'' ) || bytes. last ( ) != Some ( & b'\'' ) {
294- return false ;
295- }
296-
297- let mut idx = 1_usize ;
298- let end = bytes. len ( ) - 1 ;
299-
300- while idx < end {
301- if bytes[ idx] == b'\'' {
302- if idx + 1 < end && bytes[ idx + 1 ] == b'\'' {
303- idx += 2 ;
304- } else {
305- return false ;
306- }
307- } else {
308- idx += 1 ;
309- }
310- }
311-
312- true
140+ fn contains_only_basic_chars ( value : & str ) -> bool {
141+ value
142+ . chars ( )
143+ . all ( |c| c. is_ascii_alphanumeric ( ) || matches ! ( c, ' ' | '_' | '-' | '.' ) )
313144}
314145
315- fn is_numeric_literal ( value : & str ) -> bool {
316- let bytes = value. as_bytes ( ) ;
317- if bytes. is_empty ( ) {
318- return false ;
319- }
320-
321- let mut idx = 0_usize ;
322-
323- if matches ! ( bytes[ idx] , b'+' | b'-' ) {
324- idx += 1 ;
325- if idx >= bytes. len ( ) {
326- return false ;
327- }
328- }
329-
330- let integer_start = idx;
331- while idx < bytes. len ( ) && bytes[ idx] . is_ascii_digit ( ) {
332- idx += 1 ;
333- }
334- let has_integer_digits = idx > integer_start;
335-
336- if idx < bytes. len ( ) && bytes[ idx] == b'.' {
337- idx += 1 ;
338- let fractional_start = idx;
339- while idx < bytes. len ( ) && bytes[ idx] . is_ascii_digit ( ) {
340- idx += 1 ;
341- }
342- if !has_integer_digits && idx == fractional_start {
343- return false ;
344- }
345- } else if !has_integer_digits {
346- return false ;
347- }
348-
349- if idx < bytes. len ( ) && matches ! ( bytes[ idx] , b'e' | b'E' ) {
350- idx += 1 ;
351- if idx < bytes. len ( ) && matches ! ( bytes[ idx] , b'+' | b'-' ) {
352- idx += 1 ;
353- }
354-
355- let exponent_start = idx;
356- while idx < bytes. len ( ) && bytes[ idx] . is_ascii_digit ( ) {
357- idx += 1 ;
358- }
359-
360- if idx == exponent_start {
361- return false ;
362- }
363- }
364-
365- idx == bytes. len ( )
146+ fn is_type_cast_fragment ( value : & str ) -> bool {
147+ value. trim ( ) . chars ( ) . all ( |c| {
148+ c. is_ascii_alphanumeric ( ) || matches ! ( c, ' ' | '_' | '.' | '"' | '[' | ']' | '(' | ')' | ',' )
149+ } )
366150}
367151
368152impl ContextualPriority for Table {
@@ -402,7 +186,7 @@ mod tests {
402186 fn extracts_basic_defaults_with_optional_casts ( ) {
403187 assert_eq ! (
404188 extract_basic_default_literal( "'anonymous'::text" ) ,
405- Some ( "' anonymous' " . to_string( ) )
189+ Some ( "anonymous" . to_string( ) )
406190 ) ;
407191 assert_eq ! ( extract_basic_default_literal( "(42)::int8" ) , Some ( "42" . to_string( ) ) ) ;
408192 assert_eq ! (
@@ -426,5 +210,9 @@ mod tests {
426210 extract_basic_default_literal( "'a'::text || 'b'::text" ) ,
427211 None
428212 ) ;
213+ assert_eq ! (
214+ extract_basic_default_literal( "'with@symbol'::text" ) ,
215+ None
216+ ) ;
429217 }
430218}
0 commit comments