spacetimedb 2.0.3

Easy support for interacting between SpacetimeDB and Rust.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
# SpacetimeDB Rust Module Library

<!-- n.b. This file is used as the top-level library documentation in `src/lib.rs`.
          Some of the links in this file are not resolved when previewing on GitHub,
          but *are* resolved when compiled by Rustdoc.

          To run the doctests, run the `./bindings-doctests.sh` script.
          This works around some issues related to doctests and wasm, but it requires nightly,
          so it isn't currently run on CI.

          When you add a doc-tested code sample, make sure to copy the boilerplate around
          some other code sample, the:
          ```no_run
          # #[cfg(target_arch = "wasm32")] mod demo {
          // code
          # }
          ```
          This makes sure your samples don't break when tested on non-wasm;
          but you need to use `./bindings-doctests.sh` to actually test them.
-->

[SpacetimeDB](https://spacetimedb.com/) allows using the Rust language to write server-side applications called **modules**. Modules, which run inside a relational database, have direct access to database tables, and expose public functions called **reducers** that can be invoked over the network. Clients connect directly to the database to read data.

```text
    Client Application                          SpacetimeDB
┌───────────────────────┐                ┌───────────────────────┐
│                       │                │                       │
│  ┌─────────────────┐  │    SQL Query   │  ┌─────────────────┐  │
│  │ Subscribed Data │<─────────────────────│    Database     │  │
│  └─────────────────┘  │                │  └─────────────────┘  │
│           │           │                │           ^           │
│           │           │                │           │           │
│           v           │                │           v           │
│  +─────────────────┐  │ call_reducer() │  ┌─────────────────┐  │
│  │   Client Code   │─────────────────────>│   Module Code   │  │
│  └─────────────────┘  │                │  └─────────────────┘  │
│                       │                │                       │
└───────────────────────┘                └───────────────────────┘
```

Rust modules are written with the the Rust Module Library (this crate). They are built using [cargo](https://doc.rust-lang.org/cargo/) and deployed using the [`spacetime` CLI tool](https://spacetimedb.com/install). Rust modules can import any Rust [crate](https://crates.io/) that supports being compiled to WebAssembly.

(Note: Rust can also be used to write **clients** of SpacetimeDB databases, but this requires using a different library, the SpacetimeDB Rust Client SDK. See the documentation on [clients] for more information.)

This reference assumes you are familiar with the basics of Rust. If you aren't, check out Rust's [excellent documentation](https://www.rust-lang.org/learn). For a guided introduction to Rust Modules, see the [Rust Module Quickstart](https://spacetimedb.com/docs/modules/rust/quickstart).

## Overview

SpacetimeDB modules have two ways to interact with the outside world: tables and reducers.

- [Tables](#tables) store data and optionally make it readable by [clients]. 

- [Reducers](#reducers) are functions that modify data and can be invoked by [clients] over the network. They can read and write data in tables, and write to a private debug log.

These are the only ways for a SpacetimeDB module to interact with the outside world. Calling functions from `std::net` or `std::fs` inside a reducer will result in runtime errors.

Declaring tables and reducers is straightforward:

```no_run
# #[cfg(target_arch = "wasm32")] mod demo {
use spacetimedb::{table, reducer, ReducerContext, Table};

#[table(accessor = player)]
pub struct Player {
    id: u32,
    name: String
}

#[reducer]
fn add_person(ctx: &ReducerContext, id: u32, name: String) {
    log::debug!("Inserting {name} with id {id}");
    ctx.db.player().insert(Player { id, name });
}
# }
```


Note that reducers don't return data directly; they can only modify the database. Clients connect directly to the database and use SQL to query [public](#public-and-private-tables) tables. Clients can also subscribe to a set of rows using SQL queries and receive streaming updates whenever any of those rows change.

Tables and reducers in Rust modules can use any type that implements the [`SpacetimeType`] trait.

<!-- TODO: link to client subscriptions / client one-off queries respectively. -->

## Setup

To create a Rust module, install the [`spacetime` CLI tool](https://spacetimedb.com/install) in your preferred shell. Navigate to your work directory and run the following command:

```text
spacetime init --lang rust --project-path my-project-directory my-project
```

This creates a Cargo project in `my-project-directory` with the following `Cargo.toml`:

```text
[package]
name = "spacetime-module"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
spacetimedb = "1.0.0"
log = "0.4"
```
<!-- TODO: update `spacetimedb` version there. -->

This is a standard `Cargo.toml`, with the exception of the line `crate-type = ["cdylib"]`.
This line is important: it allows the project to be compiled to a WebAssembly module. 

The project's `lib.rs` will contain the following skeleton:

```no_run
# #[cfg(target_arch = "wasm32")] mod demo {
use spacetimedb::{ReducerContext, Table};

#[spacetimedb::table(accessor = person)]
pub struct Person {
    name: String
}

#[spacetimedb::reducer(init)]
pub fn init(_ctx: &ReducerContext) {
    // Called when the module is initially published
}

#[spacetimedb::reducer(client_connected)]
pub fn identity_connected(_ctx: &ReducerContext) {
    // Called everytime a new client connects
}

#[spacetimedb::reducer(client_disconnected)]
pub fn identity_disconnected(_ctx: &ReducerContext) {
    // Called everytime a client disconnects
}

#[spacetimedb::reducer]
pub fn add(ctx: &ReducerContext, name: String) {
    ctx.db.person().insert(Person { name });
}

#[spacetimedb::reducer]
pub fn say_hello(ctx: &ReducerContext) {
    for person in ctx.db.person().iter() {
        log::info!("Hello, {}!", person.name);
    }
    log::info!("Hello, World!");
}
# }
```

This skeleton declares a [table](#tables), some [reducers](#reducers), and some [lifecycle reducers](#lifecycle-reducers).

To compile the project, run the following command:

```text
spacetime build
```

SpacetimeDB requires a WebAssembly-compatible Rust toolchain. If the `spacetime` cli finds a compatible version of [`rustup`](https://rustup.rs/) that it can run, it will automatically install the `wasm32-unknown-unknown` target and use it to build your application. This can also be done manually using the command:

```text
rustup target add wasm32-unknown-unknown
```

If you are managing your Rust installation in some other way, you will need to install the `wasm32-unknown-unknown` target yourself.

To build your application and upload it to the public SpacetimeDB network, run:

```text
spacetime login
```

And then:

```text
spacetime publish [MY_DATABASE_NAME]
```

For example:

```text
spacetime publish silly_demo_app
```

When you publish your module, a database named `silly_demo_app` will be created with the requested tables, and the module will be installed inside it.

The output of `spacetime publish` will end with a line:
```text
Created new database with name: <name>, identity: <hex string>
```

This name is the human-readable name of the created database, and the hex string is its [`Identity`]. These distinguish the created database from the other databases running on the SpacetimeDB network.  They are used when administering the application, for example using the [`spacetime logs <DATABASE_NAME>`](#the-log-crate) command. You should probably write the database name down in a text file so that you can remember it.

After modifying your project, you can run:

`spacetime publish <DATABASE_NAME>`

to update the module attached to your database. Note that SpacetimeDB tries to [automatically migrate](#automatic-migrations) your database schema whenever you run `spacetime publish`.

You can also generate code for clients of your module using the `spacetime generate` command. See the [client SDK documentation] for more information.

## How it works

Under the hood, SpacetimeDB modules are WebAssembly modules that import a [specific WebAssembly ABI](https://spacetimedb.com/docs/webassembly-abi) and export a small number of special functions. This is automatically configured when you add the `spacetime` crate as a dependency of your application.

The SpacetimeDB host is an application that hosts SpacetimeDB databases. [Its source code is available](https://github.com/clockworklabs/SpacetimeDB) under [the Business Source License with an Additional Use Grant](https://github.com/clockworklabs/SpacetimeDB/blob/master/LICENSE.txt). You can run your own host, or you can upload your module to the public SpacetimeDB network. <!-- TODO: want a link to some dashboard for the public network. --> The network will create a database for you and install your module in it to serve client requests.

#### In More Detail: Publishing a Module

The `spacetime publish [DATABASE_IDENTITY]` command compiles a module and uploads it to a SpacetimeDB host. After this:
- The host finds the database with the requested `DATABASE_IDENTITY`.
  - (Or creates a fresh database and identity, if no identity was provided).
- The host loads the new module and inspects its requested database schema. If there are changes to the schema, the host tries perform an [automatic migration](#automatic-migrations). If the migration fails, publishing fails.
- The host terminates the old module attached to the database.
- The host installs the new module into the database. It begins running the module's [lifecycle reducers](#lifecycle-reducers) and [scheduled reducers](#scheduled-reducers), starting with the [`#[init]` reducer](macro@crate::reducer#scheduled-reducers).
- The host begins allowing clients to call the module's reducers.

From the perspective of clients, this process is seamless. Open connections are maintained and subscriptions continue functioning. [Automatic migrations](#automatic-migrations) forbid most table changes except for adding new tables, so client code does not need to be recompiled.
However:
- Clients may witness a brief interruption in the execution of scheduled reducers (for example, game loops.)
- New versions of a module may remove or change reducers that were previously present. Client code calling those reducers will receive runtime errors.


## Tables

Tables are declared using the [`#[table(accessor = table_name)]` macro](macro@crate::table).

This macro is applied to a Rust struct with named fields. All of the fields of the table must implement [`SpacetimeType`].

The resulting type is used to store rows of the table. It is normal struct type. Row values are not special -- operations on row types do not, by themselves, modify the table. Instead, a [`ReducerContext`](#reducercontext) is needed to get a handle to the table.

```no_run
# #[cfg(target_arch = "wasm32")] mod demo {
use spacetimedb::{table, reducer, ReducerContext, Table, UniqueColumn};

/// A `Person` is a row of the table `person`.
#[table(accessor = person, public)]
pub struct Person {
    #[primary_key]
    #[auto_inc]
    id: u64,
    #[index(btree)]
    name: String,
}

// `Person` is a normal Rust struct type.
// Operations on a `Person` do not, by themselves, do anything.
// The following function does not interact with the database at all.
fn do_nothing() {
    // Creating a `Person` DOES NOT modify the database.
    let mut person = Person { id: 0, name: "Joe Average".to_string() };
    // Updating a `Person` DOES NOT modify the database.
    person.name = "Joanna Average".to_string();
    // Dropping a `Person` DOES NOT modify the database.
    drop(person);
}

// To interact with the database, you need a `ReducerContext`,
// which is provided as the first parameter of any reducer.
#[reducer]
fn do_something(ctx: &ReducerContext) {
    // `ctx.db.{table_name}()` gets a handle to a database table.
    let person: &person__TableHandle = ctx.db.person();

    // The following inserts a row into the table:
    let mut example_person = person.insert(Person { id: 0, name: "Joe Average".to_string() });

    // `person` is a COPY of the row stored in the database.
    // If we update it:
    example_person.name = "Joanna Average".to_string();
    // Our copy is now updated, but the database's copy is UNCHANGED.
    // To push our change through, we can call `UniqueColumn::update()`:
    example_person = person.id().update(example_person);
    // Now the database and our copy are in sync again.
    
    // We can also delete the row in the database using `UniqueColumn::delete()`.
    person.id().delete(&example_person.id);
}
# }
```

(See [reducers](#reducers) for more information on declaring reducers.)

This library generates a custom API for each table, depending on the table's name and structure.

All tables support getting a handle implementing the [`Table`] trait from a [`ReducerContext`], using:

```text
ctx.db.{table_name}()
```

For example,

```no_build
ctx.db.person()
```

The [`Table`] trait provides:
- [`Table::insert`]
- [`Table::try_insert`]
- [`Table::delete`]
- [`Table::iter`]
- [`Table::count`]

Tables' [constraints](#unique-and-primary-key-columns) and [indexes](#indexes) generate additional accessors.

<!-- TODO: outline generated methods here, split up by annotations required. -->

#### Public and Private Tables

By default, tables are considered **private**. This means that they are only readable by the database owner and by reducers. Reducers run inside the database, so clients cannot see private tables at all.

Using the [`#[table(accessor = table_name, public)]`](macro@crate::table) flag makes a table public. **Public** tables are readable by all clients. They can still only be modified by reducers. 

```no_run
# #[cfg(target_arch = "wasm32")] mod demo {
use spacetimedb::table;

// The `enemies` table can be read by all connected clients.
#[table(accessor = enemy, public)]
pub struct Enemy {
    /* ... */
}

// The `loot_items` table is invisible to clients, but not to reducers.
#[table(accessor = loot_item)]
pub struct LootItem {
    /* ... */
}
# }
```

(Note that, when run by the module owner, the `spacetime sql <SQL_QUERY>` command can also read private tables. This is for debugging convenience. Only the module owner can see these tables. This is determined by the `Identity` stored by the `spacetime login` command. Run `spacetime login show` to print your current logged-in `Identity`.)

To learn how to subscribe to a public table, see the [client SDK documentation](https://spacetimedb.com/docs/sdks). <!-- TODO: more specific link. -->

#### Unique and Primary Key Columns

Columns of a table (that is, fields of a [`#[table]`](macro@crate::table) struct) can be annotated with [`#[unique]`](macro@crate::table#unique) or [`#[primary_key]`](macro@crate::table#primary_key). Multiple columns can be `#[unique]`, but only one can be `#[primary_key]`. For example:

```no_run
# #[cfg(target_arch = "wasm32")] mod demo {
use spacetimedb::table;

type SSN = String;
type Email = String;

#[table(accessor = citizen)]
pub struct Citizen {
    #[primary_key]
    id: u64,
    #[unique]
    ssn: SSN,
    #[unique]
    email: Email,
    name: String,
}
# }
```

Every row in the table `Person` must have unique entries in the `id`, `ssn`, and `email` columns. Attempting to insert multiple `Person`s with the same `id`, `ssn`, or `email` will fail. (Either via panic, with [`Table::insert`], or via a `Result::Err`, with [`Table::try_insert`].)

Any `#[unique]` or `#[primary_key]` column supports getting a [`UniqueColumn`] from a [`ReducerContext`] using:

```text
ctx.db.{table}().{unique_column}()
```

For example, 

```no_build
ctx.db.person().ssn()
```

[`UniqueColumn`] provides:
- [`UniqueColumn::find`]
- [`UniqueColumn::delete`]
- [`UniqueColumn::update`]
<!-- TODO: "current limitations" try_update -->

Notice that updating a row is only possible if a row has a unique column -- there is no `update` method in the base [`Table`] trait. SpacetimeDB has no notion of rows having an "identity" aside from their unique / primary keys.

The `#[primary_key]` annotation implies `#[unique]` annotation, but avails additional methods in the [client]-side SDKs.

It is not currently possible to mark a group of fields as collectively unique.

Filtering on unique columns is only supported for a limited number of types.

#### Auto-inc columns

Columns can be marked [`#[auto_inc]`](macro@crate::table#auto_inc). This can only be used on integer types (`i32`, `u8`, etc.)

When inserting into a table with an `#[auto_inc]` column, if the annotated column is set to zero (`0`), the database will automatically overwrite that zero with an atomically increasing value.

[`Table::insert`] and [`Table::try_insert`] return rows with `#[auto_inc]` columns set to the values that were actually written into the database.

**Note**: The `auto_inc` number generator is not transactional. See the [SEQUENCE] section for more details.

```no_run
# #[cfg(target_arch = "wasm32")] mod demo {
use spacetimedb::{table, reducer, ReducerContext, Table};

#[table(accessor = example)]
struct Example {
    #[auto_inc]
    field: u32
}

#[reducer]
fn insert_auto_inc_example(ctx: &ReducerContext) {
    for i in 1..=10 {
        // These will have distinct, unique values
        // at rest in the database, since they
        // are inserted with the sentinel value 0.
        let actual = ctx.db.example().insert(Example { field: 0 });
        assert!(actual.field != 0);
    }
}
# }
```

`auto_inc` is often combined with `unique` or `primary_key` to automatically assign unique integer identifiers to rows.

#### Default Values

Columns can be marked with [`#[default(value)]`](macro@crate::table#default) to specify a default value. This is primarily used for [automatic migrations](#automatic-migrations) when adding new columns to existing tables.

When you republish a module with a new column that has a default value, existing rows are automatically populated with that default. New columns must be added at the **end** of the table definition.

```no_run
# #[cfg(target_arch = "wasm32")] mod demo {
use spacetimedb::table;

#[table(accessor = player)]
struct Player {
    id: u64,
    name: String,
    // New columns added with defaults for migration
    #[default(0)]
    score: u32,
    #[default(true)]
    is_active: bool,
}
# }
```

The `#[default(value)]` attribute accepts a const-evaluable Rust expression. The value must be usable in a `const` context, which means you cannot use methods like `.to_string()` for `String` defaults. Only primitive types, enums, and other const-constructible types can have defaults.

**Constraints**: `#[default]` cannot be combined with `#[primary_key]`, `#[unique]`, or `#[auto_inc]`, as these constraints require the database to manage column values.

#### Indexes

SpacetimeDB supports both single- and multi-column [B-Tree](https://en.wikipedia.org/wiki/B-tree) indexes.

Indexes are declared using the syntax:

[`#[table(..., index(accessor = my_index, btree(columns = [a, b, c]))]`](macro@crate::table#index).

For example:

```no_run
# #[cfg(target_arch = "wasm32")] mod demo {
use spacetimedb::table;

#[table(accessor = paper, index(accessor = url_and_country, btree(columns = [url, country])))]
struct Paper {
    url: String,
    country: String,
    venue: String
} 

# }
```

Multiple indexes can be declared, separated by commas.

Single-column indexes can also be declared using the

[`#[index(btree)]`](macro@crate::table#indexbtree)

column attribute.

For example:

```no_run
# #[cfg(target_arch = "wasm32")] mod demo {
use spacetimedb::table;

#[table(accessor = paper)]
struct Paper {
    url: String,
    country: String,
    #[index(btree)]
    venue: String
} 
# }
```


Any index supports getting a [`RangedIndex`] using [`ctx`](crate::ReducerContext)`.db.{table}().{index}()`. For example, `ctx.db.person().name()`.
    
[`RangedIndex`] provides:
 - [`RangedIndex::filter`]
 - [`RangedIndex::delete`]

Only types which implement [`FilterableValue`](trait@crate::FilterableValue) may be used as index keys.

## Reducers

Reducers are declared using the [`#[reducer]` macro](macro@crate::reducer).

`#[reducer]` is always applied to top level Rust functions. Arguments of reducers must implement [`SpacetimeType`]. Reducers can either return nothing, or return a `Result<(), E>`, where `E` implements [`std::fmt::Display`].

```no_run
# #[cfg(target_arch = "wasm32")] mod demo {
use spacetimedb::{reducer, ReducerContext};
use std::fmt;

#[reducer]
fn give_player_item(
    ctx: &ReducerContext,
    player_id: u64,
    item_id: u64
) -> Result<(), String> {
    /* ... */
    # Ok(())
}
# }
```

Every reducer runs inside a [database transaction](https://en.wikipedia.org/wiki/Database_transaction). <!-- TODO: specific transaction level guarantees. --> This means that reducers will not observe the effects of other reducers modifying the database while they run. If a reducer fails, all of its changes to the database will automatically be rolled back. Reducers can fail by [panicking](::std::panic!) or by returning an `Err`.

#### The `ReducerContext` Type

Reducers have access to a special [`ReducerContext`] parameter. This parameter allows reading and writing the database attached to a module. It also provides some additional functionality, like generating random numbers and scheduling future operations.

[`ReducerContext`] provides access to the database tables via [the `.db` field](ReducerContext#structfield.db). The [`#[table]`](macro@crate::table) macro generates traits that add accessor methods to this field.

<!-- TODO: this seems to work sometimes, but not always... Sometimes the links to downstream trait implementations aren't generated for some reason. Maybe it only works in the same cargo workspace?

Yes, that's the case. Dammit. TODO: check if this changes someday.

To see all of the available methods on `ctx.db`, run `cargo doc` in your module's directory, and navigate to the `spacetimedb::Local` struct in the generated documentation. This will be at the path:
- `[your_project_directory]/target/doc/spacetimedb/struct.Local.html`
-->

#### The `log` crate

SpacetimeDB Rust modules have built-in support for the [log crate](log). All modules automatically install a suitable logger when they are first loaded by SpacetimeDB. (At time of writing, this happens [here](https://github.com/clockworklabs/SpacetimeDB/blob/e9e287b8aab638ba6e8bf9c5d41d632db041029c/crates/bindings/src/logger.rs)). Log macros can be used anywhere in module code, and log outputs of a running module can be inspected using the `spacetime logs` command:

```text
spacetime logs <DATABASE_IDENTITY>
```

<!-- TODO: we seem to have removed `println`, is that still hidden somewhere? -->

#### Lifecycle Reducers

A small group of reducers are called at set points in the module lifecycle. These are used to initialize
the database and respond to client connections. See [Lifecycle Reducers](macro@crate::reducer#lifecycle-reducers).

#### Scheduled Reducers

Reducers can schedule other reducers to run asynchronously. This allows calling the reducers at a particular time, or at repeating intervals. This can be used to implement timers, game loops, and maintenance tasks. See [Scheduled Reducers](macro@crate::reducer#scheduled-reducers).

## Views

Views are declared using the [`#[view]` macro](macro@crate::view).

Views are read‑only functions that compute and return results from your tables.
`#[view]` is always applied to top level Rust functions.
Views must be declared as `public`, with an explicit `name`, and do not accept user parameters beyond the context type.
Views can return either `Option<T>` or `Vec<T>` where `T` can be a table type or any product type in general.

```no_run
# #[cfg(target_arch = "wasm32")] mod demo {
use spacetimedb::{table, view, ViewContext, AnonymousViewContext, SpacetimeType};
use spacetimedb_lib::Identity;

#[table(accessor = player)]
struct Player {
    #[primary_key]
    #[auto_inc]
    id: u64,
    #[unique]
    identity: Identity,
    name: String,
}

#[table(accessor = player_level)]
struct PlayerLevel {
    #[unique]
    player_id: u64,
    #[index(btree)]
    level: u64,
}

#[derive(SpacetimeType)]
struct PlayerAndLevel {
    id: u64,
    identity: Identity,
    name: String,
    level: u64,
}

// At-most-one row: return Option<T>
#[view(accessor = my_player, public)]
fn my_player(ctx: &ViewContext) -> Option<Player> {
    ctx.db.player().identity().find(ctx.sender())
}

// Multiple rows: return Vec<T>
#[view(accessor = players_for_level, public)]
fn players_for_level(ctx: &AnonymousViewContext) -> Vec<PlayerAndLevel> {
    ctx.db
        .player_level()
        .level()
        .filter(2u64)
        .map(|player| {
            ctx.db
                .player()
                .id()
                .find(player.player_id)
                .map(|p| PlayerAndLevel {
                    id: p.id,
                    identity: p.identity,
                    name: p.name,
                    level: player.level,
                })
        })
        .collect()
}
# }
```

Views can be queried and subscribed to like normal tables and are updated atomically in realtime.

```sql
SELECT * FROM my_player;
SELECT * FROM players_for_level;
```

#### `ViewContext` and `AnonymousViewContext`

Views must take a `&ViewContext` or an `&AnonymousViewContext` as their first parameter.
Like reducers, these types allow reading from the database attached to a module via the `.db` field.
However, unlike reducers, they do not allow writing to the database.
Both types expose read-only portions of the `Table` and `Index` accessors generated by the [`#[table]` macro](macro@crate::table).

## Automatic migrations

When you `spacetime publish` a module that has already been published using `spacetime publish <DATABASE_NAME_OR_IDENTITY>`,
SpacetimeDB attempts to automatically migrate your existing database to the new schema. (The "schema" is just the collection
of tables and reducers you've declared in your code, together with the types they depend on.) This form of migration is limited and only supports a few kinds of changes.
On the plus side, automatic migrations usually don't break clients. The situations that may break clients are documented below.

The following changes are always allowed and never breaking:

<!-- TODO: everything here should be smoke-tested. -->

- ✅ **Adding tables**. Non-updated clients will not be able to see the new tables.
- ✅ **Adding indexes**.
- ✅ **Adding or removing `#[auto_inc]` annotations.**
- ✅ **Changing tables from private to public**.
- ✅ **Adding reducers**.
- ✅ **Removing `#[unique]`  annotations.**

The following changes are allowed, but may break clients:

- ⚠️ **Adding new columns to the end of a table with a default value**. The new column must be added at the end of the table definition and must have a default value specified. Non-updated clients will not be aware of the new column.
- ⚠️ **Changing or removing reducers**. Clients that attempt to call the old version of a changed reducer will receive runtime errors.
- ⚠️ **Changing tables from public to private**. Clients that are subscribed to a newly-private table will receive runtime errors.
- ⚠️ **Removing `#[primary_key]` annotations**. Non-updated clients will still use the old `#[primary_key]` as a unique key in their local cache, which can result in non-deterministic behavior when updates are received.
- ⚠️ **Removing indexes**. This is only breaking in some situations.
  The specific problem is subscription queries <!-- TODO: clientside link --> involving semijoins, such as:
    ```sql
    SELECT Employee.*
    FROM Employee JOIN Dept
    ON Employee.DeptName = Dept.DeptName
    )
    ```
    For performance reasons, SpacetimeDB will only allow this kind of subscription query if there are indexes on `Employee.DeptName` and `Dept.DeptName`. Removing either of these indexes will invalidate this subscription query, resulting in client-side runtime errors.

The following changes are forbidden without a manual migration:

- ❌ **Removing tables**.
- ❌ **Removing or modifying existing columns**. This includes changing the type, renaming, or reordering columns.
- ❌ **Adding columns without a default value**. New columns must have a default value so existing rows can be populated.
- ❌ **Adding columns in the middle of a table**. New columns must be added at the end of the table definition.
- ❌ **Changing whether a table is used for [scheduling](#scheduled-reducers).** <!-- TODO: update this if we ever actually implement it... -->
- ❌ **Adding `#[unique]` or `#[primary_key]` constraints.** This could result in existing tables being in an invalid state.

Currently, manual migration support is limited. The `spacetime publish --delete-data <DATABASE_IDENTITY>` command can be used to **COMPLETELY DELETE** and reinitialize your database, but naturally it should be used with EXTREME CAUTION.

[macro library]: https://github.com/clockworklabs/SpacetimeDB/tree/master/crates/bindings-macro
[module library]: https://github.com/clockworklabs/SpacetimeDB/tree/master/crates/lib
[demo]: /#demo
[client]: https://spacetimedb.com/docs/#client
[clients]: https://spacetimedb.com/docs/#client
[client SDK documentation]: https://spacetimedb.com/docs/#client
[host]: https://spacetimedb.com/docs/#host
[SEQUENCE]: https://spacetimedb.com/docs/appendix#sequence