@@ -155,7 +155,7 @@ impl QueryProject {
155155 } ;
156156 // The choice was either to relax the schema constraint to allow duplicate project names
157157 // or to append a number to the project name to ensure uniqueness.
158- let name = Self :: unique_name ( context, & query_organization, project_name) . await ?;
158+ let name = Self :: unique_name ( log , context, & query_organization, project_name) . await ?;
159159 let insert_project =
160160 InsertProject :: new ( query_organization. id , name, project_slug, None , None ) ;
161161 if let Some ( auth_user) = auth_user {
@@ -177,6 +177,7 @@ impl QueryProject {
177177 }
178178
179179 async fn unique_name (
180+ log : & Logger ,
180181 context : & ApiContext ,
181182 query_organization : & QueryOrganization ,
182183 project_name : ResourceName ,
@@ -191,20 +192,24 @@ impl QueryProject {
191192 const ELLIPSES_LEN : usize = 3 ;
192193 // The max length for a `usize` is 20 characters,
193194 // so we don't have to worry about the number suffix being too long.
194- project_name
195+ let name = project_name
195196 . as_ref ( )
196197 . chars ( )
197198 . take ( max_name_len - ELLIPSES_LEN )
198199 . chain ( "." . repeat ( ELLIPSES_LEN ) . chars ( ) )
199- . collect :: < String > ( )
200+ . collect :: < String > ( ) ;
201+ slog:: debug!( log, "Truncated project name: {name}" ) ;
202+ name
200203 } else {
201204 project_name. to_string ( )
202205 } ;
203206
204- // Escape the project name for use in a regex pattern
205- let escaped_name = regex:: escape ( & name_str) ;
207+ // Escape the project name for use in a LIKE pattern
208+ // https://www.sqlite.org/lang_expr.html#the_like_glob_regexp_match_and_extract_operators
209+ let escaped_name = name_str. replace ( '%' , r"\%" ) . replace ( '_' , r"\_" ) ;
206210 // Create a regex pattern to match the original project name or any subsequent projects with the same name
207- let pattern = format ! ( r"^{escaped_name} \(\d+\)$" ) ;
211+ let pattern = format ! ( r"{escaped_name} (%)" ) ;
212+ slog:: debug!( log, "LIKE pattern: {pattern}" ) ;
208213
209214 let Ok ( highest_name) = schema:: project:: table
210215 . filter ( schema:: project:: organization_id. eq ( query_organization. id ) )
@@ -218,10 +223,12 @@ impl QueryProject {
218223 . first :: < ResourceName > ( conn_lock ! ( context) )
219224 else {
220225 // The project name is already unique
226+ slog:: debug!( log, "Project name is unique: {project_name}" ) ;
221227 return Ok ( project_name) ;
222228 } ;
223229
224230 let next_number = if highest_name == project_name {
231+ slog:: debug!( log, "First project name duplicate: {highest_name}" ) ;
225232 1
226233 } else if let Some ( caps) = UNIQUE_SUFFIX . captures ( highest_name. as_ref ( ) ) {
227234 let last_number: usize = caps
@@ -234,6 +241,7 @@ impl QueryProject {
234241 highest_name,
235242 )
236243 } ) ?;
244+ slog:: debug!( log, "Multiple project name duplicates: {last_number}" ) ;
237245 last_number + 1
238246 } else {
239247 return Err ( issue_error (
@@ -244,6 +252,7 @@ impl QueryProject {
244252 } ;
245253
246254 let name_with_suffix = format ! ( "{name_str} ({next_number})" ) ;
255+ slog:: debug!( log, "Unique project name: {name_with_suffix}" ) ;
247256 name_with_suffix. parse ( ) . map_err ( |e| {
248257 issue_error (
249258 "Failed to create new project name" ,
0 commit comments