change the output of such query, and trigger previous memoized values to be
potentially invalidated.
### Query Groups
A query group is a set of queries which have been defined together as a unit.
The database is formed by combining query groups. Query groups are akin to
"Salsa modules".
A set of queries in a query group are just a set of methods in a trait.
To create a query group a trait annotated with a specific attribute
(`#[salsa::query_group(...)]`) has to be created.
An argument must also be provided to said attribute as it will be used by Salsa
to create a `struct` to be used later when the database is created.
Example input query group:
```rust,ignore
/// This attribute will process this tree, produce this tree as output, and produce
/// a bunch of intermediate stuff that Salsa also uses. One of these things is a
/// "StorageStruct", whose name we have specified in the attribute.
///
/// This query group is a bunch of **input** queries, that do not rely on any
/// derived input.
#[salsa::query_group(InputsStorage)]
pub trait Inputs {
/// This attribute (`#[salsa::input]`) indicates that this query is a base
/// input, therefore `set_manifest` is going to be auto-generated
#[salsa::input]
fn manifest(&self) -> Manifest;
#[salsa::input]
fn source_text(&self, name: String) -> String;
}
```
To create a **derived** query group, one must specify which other query groups
this one depends on by specifying them as supertraits, as seen in the following
example:
```rust,ignore
/// This query group is going to contain queries that depend on derived values.
/// A query group can access another query group's queries by specifying the
/// dependency as a supertrait. Query groups can be stacked as much as needed using
/// that pattern.
#[salsa::query_group(ParserStorage)]
pub trait Parser: Inputs {
/// This query `ast` is not an input query, it's a derived query this means
/// that a definition is necessary.
fn ast(&self, name: String) -> String;
}
```
When creating a derived query the implementation of said query must be defined
outside the trait. The definition must take a database parameter as an `impl
Trait` (or `dyn Trait`), where trait is the query group that the definition
belongs to, in addition to the other keys.
```rust,ignore
/// This is going to be the definition of the `ast` query in the `Parser` trait.
/// So, when the query `ast` is invoked, and it needs to be recomputed, Salsa is
/// going to call this function and it's going to give it the database as `impl
/// Parser`. The function doesn't need to be aware of all the queries of all the
/// query groups
fn ast(db: &impl Parser, name: String) -> String {
//! Note, `impl Parser` is used here but `dyn Parser` works just as well
/* code */
///By passing an `impl Parser`, this is allowed
let source_text = db.input_file(name);
/* do the actual parsing */
return ast;
}
```
Eventually, after all the query groups have been defined, the database can be
created by declaring a `struct`.
To specify which query groups are going to be part of the database an `attribute`
(`#[salsa::database(...)]`) must be added. The argument of said `attribute` is a
list of `identifiers`, specifying the query groups **storages**.
```rust,ignore
///This attribute specifies which query groups are going to be in the database
#[salsa::database(InputsStorage, ParserStorage)]
#[derive(Default)] //optional!
struct MyDatabase {
///You also need this one field
runtime : salsa::Runtime<MyDatabase>,
}
///And this trait has to be implemented
impl salsa::Database for MyDatabase {
fn salsa_runtime(&self) -> &salsa::Runtime<MyDatabase> {
&self.runtime
}
}
```
Example usage:
```rust,ignore
fn main() {
let db = MyDatabase::default();
db.set_manifest(...);
db.set_source_text(...);
loop {
db.ast(...); //will reuse results
db.set_source_text(...);
}
}
```