@@ -12,6 +12,7 @@ use syn::parse::Parse;
1212use syn:: parse:: Parser as _;
1313use syn:: punctuated:: Punctuated ;
1414use syn:: spanned:: Spanned ;
15+ use syn:: LitStr ;
1516use syn:: { parse_quote, Ident , Path , Token } ;
1617
1718pub ( crate ) struct TableArgs {
@@ -46,19 +47,21 @@ struct ScheduledArg {
4647
4748struct IndexArg {
4849 accessor : Ident ,
50+ name : Option < LitStr > ,
4951 is_unique : bool ,
5052 kind : IndexType ,
5153}
5254
5355impl IndexArg {
54- fn new ( accessor : Ident , kind : IndexType ) -> Self {
56+ fn new ( accessor : Ident , kind : IndexType , name : Option < LitStr > ) -> Self {
5557 // We don't know if its unique yet.
5658 // We'll discover this once we have collected constraints.
5759 let is_unique = false ;
5860 Self {
5961 accessor,
6062 is_unique,
6163 kind,
64+ name,
6265 }
6366 }
6467}
@@ -157,6 +160,7 @@ impl ScheduledArg {
157160impl IndexArg {
158161 fn parse_meta ( meta : ParseNestedMeta ) -> syn:: Result < Self > {
159162 let mut accessor = None ;
163+ let mut name = None ;
160164 let mut algo = None ;
161165
162166 meta. parse_nested_meta ( |meta| {
@@ -165,6 +169,11 @@ impl IndexArg {
165169 check_duplicate( & accessor, & meta) ?;
166170 accessor = Some ( meta. value( ) ?. parse( ) ?) ;
167171 }
172+ sym:: name => {
173+ check_duplicate( & name, & meta) ?;
174+ let litstr: LitStr = meta. value( ) ?. parse( ) ?;
175+ name = Some ( litstr) ;
176+ }
168177 sym:: btree => {
169178 check_duplicate_msg( & algo, & meta, "index algorithm specified twice" ) ?;
170179 algo = Some ( Self :: parse_btree( meta) ?) ;
@@ -188,7 +197,7 @@ impl IndexArg {
188197 )
189198 } ) ?;
190199
191- Ok ( IndexArg :: new ( accessor, kind) )
200+ Ok ( IndexArg :: new ( accessor, kind, name ) )
192201 }
193202
194203 fn parse_columns ( meta : & ParseNestedMeta ) -> syn:: Result < Option < Vec < Ident > > > {
@@ -248,6 +257,8 @@ impl IndexArg {
248257 /// Parses an inline `#[index(btree)]`, `#[index(hash)]`, or `#[index(direct)]` attribute on a field.
249258 fn parse_index_attr ( field : & Ident , attr : & syn:: Attribute ) -> syn:: Result < Self > {
250259 let mut kind = None ;
260+ let mut accessor: Option < Ident > = None ;
261+ let mut name: Option < LitStr > = None ;
251262 attr. parse_nested_meta ( |meta| {
252263 match_meta ! ( match meta {
253264 sym:: btree => {
@@ -266,13 +277,27 @@ impl IndexArg {
266277 check_duplicate_msg( & kind, & meta, "index type specified twice" ) ?;
267278 kind = Some ( IndexType :: Direct { column: field. clone( ) } )
268279 }
280+ sym:: accessor => {
281+ check_duplicate( & accessor, & meta) ?;
282+ accessor = Some ( meta. value( ) ?. parse( ) ?) ;
283+ }
284+ sym:: name => {
285+ check_duplicate( & name, & meta) ?;
286+ name = Some ( meta. value( ) ?. parse( ) ?) ;
287+ }
269288 } ) ;
270289 Ok ( ( ) )
271290 } ) ?;
272- let kind = kind
273- . ok_or_else ( || syn:: Error :: new_spanned ( & attr. meta , "must specify kind of index (`btree` or `direct`)" ) ) ?;
274- let name = field. clone ( ) ;
275- Ok ( IndexArg :: new ( name, kind) )
291+ let kind = kind. ok_or_else ( || {
292+ syn:: Error :: new_spanned (
293+ & attr. meta ,
294+ "must specify kind of index (`btree` , `direct`, `name` or `value`)" ,
295+ )
296+ } ) ?;
297+
298+ // Default accessor = field name if not provided
299+ let accessor = accessor. unwrap_or_else ( || field. clone ( ) ) ;
300+ Ok ( IndexArg :: new ( accessor, kind, name) )
276301 }
277302
278303 fn validate < ' a > ( & ' a self , table_name : & str , cols : & ' a [ Column < ' a > ] ) -> syn:: Result < ValidatedIndex < ' a > > {
@@ -299,17 +324,19 @@ impl IndexArg {
299324 ( ValidatedIndexType :: Direct { col } , "direct" )
300325 }
301326 } ;
302- // See crates/schema/src/validate/v9.rs for the format of index names.
303- // It's slightly unnerving that we just trust that component to generate this format correctly,
304- // but what can you do.
305- let cols = kind. columns ( ) ;
306- let cols = cols. iter ( ) . map ( |col| col. ident . to_string ( ) ) . collect :: < Vec < _ > > ( ) ;
307- let cols = cols. join ( "_" ) ;
308- let index_name = format ! ( "{table_name}_{cols}_idx_{kind_str}" ) ;
327+ let gen_index_name = || {
328+ // See crates/schema/src/validate/v9.rs for the format of index names.
329+ // It's slightly unnerving that we just trust that component to generate this format correctly,
330+ // but what can you do.
331+ let cols = kind. columns ( ) ;
332+ let cols = cols. iter ( ) . map ( |col| col. ident . to_string ( ) ) . collect :: < Vec < _ > > ( ) ;
333+ let cols = cols. join ( "_" ) ;
334+ format ! ( "{table_name}_{cols}_idx_{kind_str}" )
335+ } ;
309336
310337 Ok ( ValidatedIndex {
311338 is_unique : self . is_unique ,
312- index_name,
339+ index_name : self . name . as_ref ( ) . map ( |s| s . value ( ) ) . unwrap_or_else ( gen_index_name ) ,
313340 accessor_name : & self . accessor ,
314341 kind,
315342 } )
@@ -417,10 +444,12 @@ impl ValidatedIndex<'_> {
417444 }
418445 } ;
419446 let accessor_name = ident_to_litstr ( self . accessor_name ) ;
447+ let index_name = & self . index_name ;
420448 // Note: we do not pass the index_name through here.
421449 // We trust the schema validation logic to reconstruct the name we've stored in `self.name`.
422450 quote ! ( spacetimedb:: table:: IndexDesc {
423451 accessor_name: #accessor_name,
452+ index_name: #index_name,
424453 algo: #algo,
425454 } )
426455 }
@@ -800,10 +829,11 @@ pub(crate) fn table_impl(mut args: TableArgs, item: &syn::DeriveInput) -> syn::R
800829 // NOTE(centril): We pick `btree` here if the user does not specify otherwise,
801830 // as it's the safest choice of index for the general case,
802831 // even if isn't optimal in specific cases.
803- let name = unique_col. ident . clone ( ) ;
804- let columns = vec ! [ name . clone( ) ] ;
832+ let accessor = unique_col. ident . clone ( ) ;
833+ let columns = vec ! [ accessor . clone( ) ] ;
805834 args. indices . push ( IndexArg {
806- accessor : name,
835+ accessor,
836+ name : None ,
807837 is_unique : true ,
808838 kind : IndexType :: BTree { columns } ,
809839 } )
0 commit comments