Skip to content

Commit 076a026

Browse files
committed
define name -> accessor in views, reducer and table
1 parent 9aa1cfb commit 076a026

15 files changed

Lines changed: 84 additions & 66 deletions

File tree

crates/bindings-macro/src/procedure.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ impl ProcedureArgs {
2929
}
3030
}
3131

32-
pub(crate) fn procedure_impl(args: ProcedureArgs, original_function: &ItemFn) -> syn::Result<TokenStream> {
32+
pub(crate) fn procedure_impl(_args: ProcedureArgs, original_function: &ItemFn) -> syn::Result<TokenStream> {
3333
let func_name = &original_function.sig.ident;
3434
let vis = &original_function.vis;
3535

36-
let procedure_name = args.name.unwrap_or_else(|| ident_to_litstr(func_name));
36+
let procedure_name = ident_to_litstr(func_name);
3737

3838
assert_only_lifetime_generics(original_function, "procedures")?;
3939

crates/bindings-macro/src/reducer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ pub(crate) fn reducer_impl(args: ReducerArgs, original_function: &ItemFn) -> syn
9696
let func_name = &original_function.sig.ident;
9797
let vis = &original_function.vis;
9898

99-
let reducer_name = args.name.unwrap_or_else(|| ident_to_litstr(func_name));
99+
let reducer_name = ident_to_litstr(func_name);
100100

101101
assert_only_lifetime_generics(original_function, "reducers")?;
102102

crates/bindings-macro/src/table.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use syn::{parse_quote, Ident, Path, Token};
1717

1818
pub(crate) struct TableArgs {
1919
access: Option<TableAccess>,
20+
_name: Option<LitStr>,
2021
scheduled: Option<ScheduledArg>,
2122
accessor: Ident,
2223
indices: Vec<IndexArg>,
@@ -77,6 +78,7 @@ impl TableArgs {
7778
let mut access = None;
7879
let mut scheduled = None;
7980
let mut accessor = None;
81+
let mut name = None;
8082
let mut indices = Vec::new();
8183
syn::meta::parser(|meta| {
8284
match_meta!(match meta {
@@ -93,6 +95,11 @@ impl TableArgs {
9395
let value = meta.value()?;
9496
accessor = Some(value.parse()?);
9597
}
98+
sym::name => {
99+
check_duplicate(&accessor, &meta)?;
100+
let value = meta.value()?;
101+
name = Some(value.parse()?);
102+
}
96103
sym::index => indices.push(IndexArg::parse_meta(meta)?),
97104
sym::scheduled => {
98105
check_duplicate(&scheduled, &meta)?;
@@ -114,6 +121,7 @@ impl TableArgs {
114121
scheduled,
115122
accessor,
116123
indices,
124+
_name: name,
117125
})
118126
}
119127
}

crates/bindings-macro/src/view.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,53 +3,63 @@ use proc_macro2::{Ident, Span, TokenStream};
33
use quote::quote;
44
use syn::ext::IdentExt;
55
use syn::parse::Parser;
6-
use syn::{FnArg, ItemFn};
6+
use syn::{FnArg, ItemFn, LitStr};
77

88
use crate::sym;
99
use crate::util::{check_duplicate_msg, match_meta};
1010

1111
pub(crate) struct ViewArgs {
12-
name: Ident,
12+
_name: Option<LitStr>,
13+
accessor: Ident,
1314
#[allow(unused)]
1415
public: bool,
1516
}
1617

1718
impl ViewArgs {
18-
/// Parse `#[view(name = ..., public)]` where both `name` and `public` are required.
19+
/// Parse `#[view(accessor = ..., public)]` where both `name` and `public` are required.
1920
pub(crate) fn parse(input: TokenStream, func_ident: &Ident) -> syn::Result<Self> {
2021
let mut name = None;
22+
let mut accessor = None;
2123
let mut public = None;
2224
syn::meta::parser(|meta| {
2325
match_meta!(match meta {
2426
sym::name => {
2527
check_duplicate_msg(&name, &meta, "`name` already specified")?;
26-
name = Some(meta.value()?.parse()?);
28+
name = Some(meta.value()?.parse::<LitStr>()?);
2729
}
2830
sym::public => {
2931
check_duplicate_msg(&public, &meta, "`public` already specified")?;
3032
public = Some(());
3133
}
34+
sym::accessor => {
35+
check_duplicate_msg(&accessor, &meta, "`accessor` already specified")?;
36+
accessor = Some(meta.value()?.parse()?);
37+
}
3238
});
3339
Ok(())
3440
})
3541
.parse2(input)?;
36-
let name = name.ok_or_else(|| {
42+
let accessor = accessor.ok_or_else(|| {
3743
let view = func_ident.to_string().to_snake_case();
3844
syn::Error::new(
3945
Span::call_site(),
40-
format_args!("must specify view name, e.g. `#[spacetimedb::view(name = {view})]"),
46+
format_args!("must specify view accessor, e.g. `#[spacetimedb::view(accessor = {view})]"),
4147
)
4248
})?;
4349
let () = public
4450
.ok_or_else(|| syn::Error::new(Span::call_site(), "views must be `public`, e.g. `#[view(public)]`"))?;
45-
Ok(Self { name, public: true })
51+
Ok(Self {
52+
_name: name,
53+
public: true,
54+
accessor,
55+
})
4656
}
4757
}
4858

4959
pub(crate) fn view_impl(args: ViewArgs, original_function: &ItemFn) -> syn::Result<TokenStream> {
5060
let vis = &original_function.vis;
5161
let func_name = &original_function.sig.ident;
52-
let view_ident = args.name;
62+
let view_ident = args.accessor;
5363
let view_name = view_ident.unraw().to_string();
5464

5565
for param in &original_function.sig.generics.params {

crates/bindings/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -606,13 +606,13 @@ struct PlayerAndLevel {
606606
}
607607
608608
// At-most-one row: return Option<T>
609-
#[view(name = my_player, public)]
609+
#[view(accessor = my_player, public)]
610610
fn my_player(ctx: &ViewContext) -> Option<Player> {
611611
ctx.db.player().identity().find(ctx.sender())
612612
}
613613
614614
// Multiple rows: return Vec<T>
615-
#[view(name = players_for_level, public)]
615+
#[view(accessor = players_for_level, public)]
616616
fn players_for_level(ctx: &AnonymousViewContext) -> Vec<PlayerAndLevel> {
617617
ctx.db
618618
.player_level()

crates/bindings/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -814,19 +814,19 @@ pub use spacetimedb_bindings_macro::procedure;
814814
/// }
815815
///
816816
/// // A view that selects at most one row from a table
817-
/// #[view(name = my_player, public)]
817+
/// #[view(accessor = my_player, public)]
818818
/// fn my_player(ctx: &ViewContext) -> Option<Player> {
819819
/// ctx.db.player().identity().find(ctx.sender())
820820
/// }
821821
///
822822
/// // An example of column projection
823-
/// #[view(name = my_player_id, public)]
823+
/// #[view(accessor = my_player_id, public)]
824824
/// fn my_player_id(ctx: &ViewContext) -> Option<PlayerId> {
825825
/// ctx.db.player().identity().find(ctx.sender()).map(|Player { id, .. }| PlayerId { id })
826826
/// }
827827
///
828828
/// // An example that is analogous to a semijoin in sql
829-
/// #[view(name = players_at_coordinates, public)]
829+
/// #[view(accessor = players_at_coordinates, public)]
830830
/// fn players_at_coordinates(ctx: &AnonymousViewContext) -> Vec<Player> {
831831
/// ctx
832832
/// .db
@@ -838,7 +838,7 @@ pub use spacetimedb_bindings_macro::procedure;
838838
/// }
839839
///
840840
/// // An example of a join that combines fields from two different tables
841-
/// #[view(name = players_with_coordinates, public)]
841+
/// #[view(accessor = players_with_coordinates, public)]
842842
/// fn players_with_coordinates(ctx: &AnonymousViewContext) -> Vec<PlayerAndLocation> {
843843
/// ctx
844844
/// .db

crates/bindings/tests/ui/views-more.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ struct PlayerInfo {
99
age: u8,
1010
}
1111
/// Comparing incompatible types in `where` condition: u8 != u32 implicitly
12-
#[view(name = view_bad_where_int_types_implicit, public)]
12+
#[view(accessor = view_bad_where_int_types_implicit, public)]
1313
fn view_bad_where_int_types_implicit(ctx: &ViewContext) -> Query<PlayerInfo> {
1414
ctx.from.player_info().r#where(|a| a.age.eq(4200)).build()
1515
}

crates/bindings/tests/ui/views.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -73,73 +73,73 @@ struct Player {
7373
struct NotSpacetimeType {}
7474

7575
/// Private views not allowed; must be `#[view(public, ...)]`
76-
#[view(name = view_def_no_public)]
76+
#[view(accessor = view_def_no_public)]
7777
fn view_def_no_public(_: &ViewContext) -> Vec<Player> {
7878
vec![]
7979
}
8080

8181
/// Duplicate `public`
82-
#[view(name = view_def_dup_public, public, public)]
82+
#[view(accessor = view_def_dup_public, public, public)]
8383
fn view_def_dup_public() -> Vec<Player> {
8484
vec![]
8585
}
8686

8787
/// Duplicate `name`
88-
#[view(name = view_def_dup_name, name = view_def_dup_name, public)]
88+
#[view(accessor = view_def_dup_name, name = view_def_dup_name, public)]
8989
fn view_def_dup_name() -> Vec<Player> {
9090
vec![]
9191
}
9292

9393
/// Unsupported attribute arg
94-
#[view(name = view_def_unsupported_arg, public, anonymous)]
94+
#[view(accessor = view_def_unsupported_arg, public, anonymous)]
9595
fn view_def_unsupported_arg() -> Vec<Player> {
9696
vec![]
9797
}
9898

9999
/// A `ViewContext` is required
100-
#[view(name = view_def_no_context, public)]
100+
#[view(accessor = view_def_no_context, public)]
101101
fn view_def_no_context() -> Vec<Player> {
102102
vec![]
103103
}
104104

105105
/// A `ViewContext` is required
106-
#[view(name = view_def_wrong_context, public)]
106+
#[view(accessor = view_def_wrong_context, public)]
107107
fn view_def_wrong_context(_: &ReducerContext) -> Vec<Player> {
108108
vec![]
109109
}
110110

111111
/// Must pass the `ViewContext` by ref
112-
#[view(name = view_def_pass_context_by_value, public)]
112+
#[view(accessor = view_def_pass_context_by_value, public)]
113113
fn view_def_pass_context_by_value(_: ViewContext) -> Vec<Player> {
114114
vec![]
115115
}
116116

117117
/// The view context must be the first parameter
118-
#[view(name = view_def_wrong_context_position, public)]
118+
#[view(accessor = view_def_wrong_context_position, public)]
119119
fn view_def_wrong_context_position(_: &u32, _: &ViewContext) -> Vec<Player> {
120120
vec![]
121121
}
122122

123123
/// Must return `Vec<T>` or `Option<T>` where `T` is a SpacetimeType
124-
#[view(name = view_def_no_return, public)]
124+
#[view(accessor = view_def_no_return, public)]
125125
fn view_def_no_return(_: &ViewContext) {}
126126

127127
/// Must return `Vec<T>` or `Option<T>` where `T` is a SpacetimeType
128-
#[view(name = view_def_wrong_return, public)]
128+
#[view(accessor = view_def_wrong_return, public)]
129129
fn view_def_wrong_return(_: &ViewContext) -> Player {
130130
Player {
131131
identity: Identity::ZERO,
132132
}
133133
}
134134

135135
/// Must return `Vec<T>` or `Option<T>` where `T` is a SpacetimeType
136-
#[view(name = view_def_returns_not_a_spacetime_type, public)]
136+
#[view(accessor = view_def_returns_not_a_spacetime_type, public)]
137137
fn view_def_returns_not_a_spacetime_type(_: &AnonymousViewContext) -> Option<NotSpacetimeType> {
138138
None
139139
}
140140

141141
/// Cannot use a view as a scheduled function
142-
#[view(name = sched_table_view, public)]
142+
#[view(accessor = sched_table_view, public)]
143143
fn sched_table_view(_: &ViewContext, _args: ScheduledTable) -> Vec<PlayerInfo> {
144144
vec![]
145145
}
@@ -155,20 +155,20 @@ struct PlayerInfo {
155155
}
156156

157157
/// Comparing incompatible types in `where` condition: Identity != int
158-
#[view(name = view_bad_where, public)]
158+
#[view(accessor = view_bad_where, public)]
159159
fn view_bad_where(ctx: &ViewContext) -> Query<Player> {
160160
ctx.from.player().r#where(|a| a.identity.eq(42)).build()
161161
}
162162

163163
/// Comparing incompatible types in `where` condition: u8 != u32
164-
#[view(name = view_bad_where_int_types, public)]
164+
#[view(accessor = view_bad_where_int_types, public)]
165165
fn view_bad_where_int_types(ctx: &ViewContext) -> Query<PlayerInfo> {
166166
ctx.from.player_info().r#where(|a| a.age.eq(4200u32)).build()
167167
}
168168

169169
/// Joining incompatible types
170170
/// -- weight is u32, identity is Identity
171-
#[view(name = view_bad_join, public)]
171+
#[view(accessor = view_bad_join, public)]
172172
fn view_bad_join(ctx: &ViewContext) -> Query<PlayerInfo> {
173173
ctx.from
174174
.player_info()
@@ -178,7 +178,7 @@ fn view_bad_join(ctx: &ViewContext) -> Query<PlayerInfo> {
178178

179179
/// Joining non-index columns
180180
/// -- age is not indexed
181-
#[view(name = view_join_non_indexed_column, public)]
181+
#[view(accessor = view_join_non_indexed_column, public)]
182182
fn view_join_non_indexed_column(ctx: &ViewContext) -> Query<PlayerInfo> {
183183
ctx.from
184184
.player()
@@ -188,7 +188,7 @@ fn view_join_non_indexed_column(ctx: &ViewContext) -> Query<PlayerInfo> {
188188

189189
/// Right join returns right table's type
190190
/// -- should be PlayerInfo, not Player
191-
#[view(name = view_right_join_wrong_return_type, public)]
191+
#[view(accessor = view_right_join_wrong_return_type, public)]
192192
fn view_right_join_wrong_return_type(ctx: &ViewContext) -> Query<Player> {
193193
ctx.from
194194
.player()
@@ -198,7 +198,7 @@ fn view_right_join_wrong_return_type(ctx: &ViewContext) -> Query<Player> {
198198

199199
/// Using non-existent table
200200
/// -- xyz table does not exist
201-
#[view(name = view_nonexistent_table, public)]
201+
#[view(accessor = view_nonexistent_table, public)]
202202
fn view_nonexistent_table(ctx: &ViewContext) -> Query<T> {
203203
ctx.from.xyz().build()
204204
}

0 commit comments

Comments
 (0)