Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Named Queries #2588

Closed
lizelive opened this issue Aug 2, 2021 · 5 comments
Closed

Named Queries #2588

lizelive opened this issue Aug 2, 2021 · 5 comments
Assignees
Labels
A-ECS Entities, components, systems, and events C-Docs An addition or correction to our documentation

Comments

@lizelive
Copy link

lizelive commented Aug 2, 2021

What problem does this solve or what need does it fill?

The most simple of systems require a lot of ugly boiler plate code such as:

  1. a for loop
  2. destructing operations
  3. hard to read queries
  4. hard to debug

What solution would you like?

#[derive(Query)]
pub struct PointMassQuery{
    position: &mut Position,
    momentum: &Momentum,
    mass: &Mass
}

pub fn newtons_first_law(point_mass: PointMassQuerry, time: Res<Time>) {
    point_mass.position += time.delta_seconds() * point_mass.momentum / point_mass.mass;
}

fn system_with_queryable(q: Query<PointMassQuery>) {}

What alternative(s) have you considered?

#2252 but that requires all param to be mutable to be useful. it is possible to make a macro to generate an all inclusive named query for early development to address this use case.
The old school for-each sytanx but that is not very flexible

Additional context

Figuring this out will make the relation system way cleaner and more usable.

@lizelive lizelive added C-Feature A new feature, making something new possible S-Needs-Triage This issue needs to be labelled labels Aug 2, 2021
@lizelive lizelive changed the title Named Queries / ForEach Named Queries Aug 2, 2021
@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events and removed S-Needs-Triage This issue needs to be labelled labels Aug 2, 2021
@cart
Copy link
Member

cart commented Aug 4, 2021

I think this is actually multiple orthogonal requests:

Named Queries

Named queries are already possible in a number of ways:

Type Aliases

pub type PointMassFetch<'a> = (&'a mut Position, &'a Momentum, &'a Mass);
fn newtons_first_law(query: Query<PointMassFetch>, time: Res<Time>) {
}
pub type PointMassQuery<'a> = Query<'a, 'a, (&'a mut Position, &'a Momentum, &'a Mass)>;
fn newtons_first_law(query: PointMassQuery, time: Res<Time>) {
}

We are also currently experimenting with "lifetimeless fetch impls" in the new renderer, which would look like this:

pub type PointMassFetch = (Write<Position>, Read<Momentum>, Read<Mass>);
fn newtons_first_law(query: Query<PointMassFetch>, time: Res<Time>) {
}

SystemParam derives

#[derive(SystemParam)]
struct PointMassQuery<'a> {
    query: Query<(&'a mut Position, &'a Momentum, &'a Mass)>,
}

Fetch Derives

Some people would prefer to access query results with pre-defined field names instead of typing them out on the "left hand side" in the returned tuple. This is a relatively straightforward derive impl.

#[derive(Fetch)]
pub struct PointMassFetch {
    position: &mut Position,
    momentum: &Momentum,
    mass: &Mass
}


pub fn newtons_first_law(point_mass: Query<PointMassFetch>, time: Res<Time>) {
}

Single-entity "for-each" systems

Bring back for-each systems by allowing Fetch alongside system parameters. This will be a divisive topic (that deserves its own issue) because they were removed (for good reasons) in #798.

@Nilirad
Copy link
Contributor

Nilirad commented Aug 6, 2021

We are also currently experimenting with "lifetimeless fetch impls" in the new renderer, which would look like this:

pub type PointMassFetch = (Write<Position>, Read<Momentum>, Read<Mass>);
fn newtons_first_law(query: Query<PointMassFetch>, time: Res<Time>) {
}

Would it be virtually possible to have a Removed<T> fetch such that it retrieves a component that has just been removed? I think it could be the best solution for #2148.

@tigregalis
Copy link
Contributor

I think this is actually multiple orthogonal requests:

Named Queries

Fetch Derives

This really needs to be documented in the book. Is it documented in the book?

@Nilirad
Copy link
Contributor

Nilirad commented Sep 26, 2021

@tigregalis I gave a glance at the WIP new book and it looks that named queries are not currently documented. @alice-i-cecile what do you think about adding query type aliases and/or #[derive(SystemParam)] as patterns for named queries?

Fetch derives are not merged yet, but they can also be documented somewhere once they are.

@alice-i-cecile
Copy link
Member

Yep, I'm on board with mentioning those in the ECS chapter! Feel free to leave a note on that PR; or make a PR to my branch to add them.

@alice-i-cecile alice-i-cecile added C-Docs An addition or correction to our documentation and removed C-Feature A new feature, making something new possible labels Dec 12, 2021
@alice-i-cecile alice-i-cecile self-assigned this Dec 12, 2021
@bors bors bot closed this as completed in ba6b74b Feb 24, 2022
kurtkuehnert pushed a commit to kurtkuehnert/bevy that referenced this issue Mar 6, 2022
# Objective

- Closes bevyengine#786
- Closes bevyengine#2252
- Closes bevyengine#2588

This PR implements a derive macro that allows users to define their queries as structs with named fields.

## Example

```rust
#[derive(WorldQuery)]
#[world_query(derive(Debug))]
struct NumQuery<'w, T: Component, P: Component> {
    entity: Entity,
    u: UNumQuery<'w>,
    generic: GenericQuery<'w, T, P>,
}

#[derive(WorldQuery)]
#[world_query(derive(Debug))]
struct UNumQuery<'w> {
    u_16: &'w u16,
    u_32_opt: Option<&'w u32>,
}

#[derive(WorldQuery)]
#[world_query(derive(Debug))]
struct GenericQuery<'w, T: Component, P: Component> {
    generic: (&'w T, &'w P),
}

#[derive(WorldQuery)]
#[world_query(filter)]
struct NumQueryFilter<T: Component, P: Component> {
    _u_16: With<u16>,
    _u_32: With<u32>,
    _or: Or<(With<i16>, Changed<u16>, Added<u32>)>,
    _generic_tuple: (With<T>, With<P>),
    _without: Without<Option<u16>>,
    _tp: PhantomData<(T, P)>,
}

fn print_nums_readonly(query: Query<NumQuery<u64, i64>, NumQueryFilter<u64, i64>>) {
    for num in query.iter() {
        println!("{:#?}", num);
    }
}

#[derive(WorldQuery)]
#[world_query(mutable, derive(Debug))]
struct MutNumQuery<'w, T: Component, P: Component> {
    i_16: &'w mut i16,
    i_32_opt: Option<&'w mut i32>,
}

fn print_nums(mut query: Query<MutNumQuery, NumQueryFilter<u64, i64>>) {
    for num in query.iter_mut() {
        println!("{:#?}", num);
    }
}
```

## TODOs:
- [x] Add support for `&T` and `&mut T`
  - [x] Test
- [x] Add support for optional types
  - [x] Test
- [x] Add support for `Entity`
  - [x] Test
- [x] Add support for nested `WorldQuery`
  - [x] Test
- [x] Add support for tuples
  - [x] Test
- [x] Add support for generics
  - [x] Test
- [x] Add support for query filters
  - [x] Test
- [x] Add support for `PhantomData`
  - [x] Test
- [x] Refactor `read_world_query_field_type_info`
- [x] Properly document `readonly` attribute for nested queries and the static assertions that guarantee safety
  - [x] Test that we never implement `ReadOnlyFetch` for types that need mutable access
  - [x] Test that we insert static assertions for nested `WorldQuery` that a user marked as readonly
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Docs An addition or correction to our documentation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants