@@ -243,10 +243,6 @@ impl IndexArg {
243243 check_duplicate( & accessor, & meta) ?;
244244 accessor = Some ( meta. value( ) ?. parse( ) ?) ;
245245 }
246- sym:: name => {
247- check_duplicate( & canonical_name, & meta) ?;
248- canonical_name = Some ( meta. value( ) ?. parse( ) ?) ;
249- }
250246
251247 sym:: btree => {
252248 check_duplicate_msg( & algo, & meta, "index algorithm specified twice" ) ?;
@@ -263,40 +259,33 @@ impl IndexArg {
263259 sym:: name => {
264260 // If the user is trying to specify a `name`, do a bit of guessing at what their goal is.
265261 // This is going to be best-effort, and we're not going to try to do lookahead or anything.
266-
267- return Err ( if accessor. is_some( ) {
268- // If the user's already specified an `accessor`,
269- // then probably they're trying to specify the canonical name,
270- // like you can for tables.
271- // Print an error that says this is unsupported.
272- meta. error(
273- "Unexpected argument `name` in index definition.
274-
275- Overwriting the `name` of an index is currently unsupported." ,
276- )
277- } else if let Ok ( sym) = meta. value( ) . and_then( |val| val. parse:: <Ident >( ) ) {
262+ let val = meta. value( ) ?;
263+
264+ if let Ok ( name) = val. parse:: <LitStr >( ) {
265+ // User provided a string literal - use it as custom index name
266+ check_duplicate( & canonical_name, & meta) ?;
267+ canonical_name = Some ( name) ;
268+ } else if accessor. is_none( )
269+ && let Ok ( sym) = val. parse:: <Ident >( )
270+ {
278271 // If we haven't seen an `accessor` yet, and the value is an ident,
279272 // then probably this is 1.* syntax that needs a migration.
280273 // Note that, if the user specifies `name = {ident}` followed by `accessor = {ident}`,
281274 // we'll hit this branch, even though the diagnostic doesn't apply and we'd prefer not to.
282275 // I (pgoldman 2026-02-18) don't see a good way to distinguish this case
283276 // without making our parsing dramatically more complicated,
284277 // and it seems unlikely to occur.
285- meta. error( format_args!(
278+ return Err ( meta. error( format_args!(
286279 "Expected an `accessor` in index definition, but got a `name` instead.
287280
288- If you're migrating from SpacetimeDB 1.*, replace `name = {sym}` with `accessor = {sym}`."
289- ) )
281+ If you're migrating from SpacetimeDB 1.*, replace `name = {sym}` with `accessor = {sym}`.
282+ If you want to specify custom index name use string literal, , replace `name = {sym}` with `name = \" {sym}\" `"
283+ ) ) ) ;
290284 } else {
291- // If we haven't seen an `accessor` yet, but the value is not an ident,
292- // then we're not really sure what's going wrong, so print a more generic error message.
293- meta. error( format_args!(
294- "Unexpected argument `name` in index definition.
295-
296- Overwriting the `name` of an index is currently unsupported.
297- Did you mean to specify an `accessor` instead? Do so with `accessor = my_index`, where `my_index` is an unquoted identifier."
298- ) )
299- } ) ;
285+ return Err ( meta. error( format_args!(
286+ "Use a string literal for a custom index name: `name = \" {val}\" `." ,
287+ ) ) ) ;
288+ }
300289 }
301290 } ) ;
302291 Ok ( ( ) )
@@ -369,6 +358,7 @@ Did you mean to specify an `accessor` instead? Do so with `accessor = my_index`,
369358 /// Parses an inline `#[index(btree)]`, `#[index(hash)]`, or `#[index(direct)]` attribute on a field.
370359 fn parse_index_attr ( field : & Ident , attr : & syn:: Attribute ) -> syn:: Result < Self > {
371360 let mut kind = None ;
361+ let mut name = None ;
372362 attr. parse_nested_meta ( |meta| {
373363 match_meta ! ( match meta {
374364 sym:: btree => {
@@ -387,6 +377,10 @@ Did you mean to specify an `accessor` instead? Do so with `accessor = my_index`,
387377 check_duplicate_msg( & kind, & meta, "index type specified twice" ) ?;
388378 kind = Some ( IndexType :: Direct { column: field. clone( ) } )
389379 }
380+ sym:: name => {
381+ check_duplicate( & name, & meta) ?;
382+ name = Some ( meta. value( ) ?. parse( ) ?) ;
383+ }
390384 } ) ;
391385 Ok ( ( ) )
392386 } ) ?;
@@ -395,7 +389,7 @@ Did you mean to specify an `accessor` instead? Do so with `accessor = my_index`,
395389
396390 // Default accessor = field name if not provided
397391 let accessor = field. clone ( ) ;
398- Ok ( IndexArg :: new ( accessor, kind, None ) )
392+ Ok ( IndexArg :: new ( accessor, kind, name ) )
399393 }
400394
401395 fn validate < ' a > ( & ' a self , table_name : & str , cols : & ' a [ Column < ' a > ] ) -> syn:: Result < ValidatedIndex < ' a > > {
@@ -436,7 +430,10 @@ Did you mean to specify an `accessor` instead? Do so with `accessor = my_index`,
436430 is_unique : self . is_unique ,
437431 // This must be the canonical name (name used internally in database),
438432 // as it is used in `index_id_from_name` abi.
439- index_name : gen_index_name ( ) ,
433+ index_name : match self . canonical_name . as_ref ( ) {
434+ Some ( s) => s. value ( ) ,
435+ None => gen_index_name ( ) ,
436+ } ,
440437 accessor_name : & self . accessor ,
441438 kind,
442439 canonical_name : self . canonical_name . as_ref ( ) . map ( |s| s. value ( ) ) ,
0 commit comments