bevy_ecs/relationship/
mod.rs

1//! This module provides functionality to link entities to each other using specialized components called "relationships". See the [`Relationship`] trait for more info.
2
3mod related_methods;
4mod relationship_query;
5mod relationship_source_collection;
6
7use core::marker::PhantomData;
8
9use alloc::format;
10
11use bevy_utils::prelude::DebugName;
12pub use related_methods::*;
13pub use relationship_query::*;
14pub use relationship_source_collection::*;
15
16use crate::{
17    component::{Component, ComponentCloneBehavior, Mutable},
18    entity::{ComponentCloneCtx, Entity},
19    error::CommandWithEntity,
20    lifecycle::HookContext,
21    world::{DeferredWorld, EntityWorldMut},
22};
23use log::warn;
24
25/// A [`Component`] on a "source" [`Entity`] that references another target [`Entity`], creating a "relationship" between them. Every [`Relationship`]
26/// has a corresponding [`RelationshipTarget`] type (and vice-versa), which exists on the "target" entity of a relationship and contains the list of all
27/// "source" entities that relate to the given "target"
28///
29/// The [`Relationship`] component is the "source of truth" and the [`RelationshipTarget`] component reflects that source of truth. When a [`Relationship`]
30/// component is inserted on an [`Entity`], the corresponding [`RelationshipTarget`] component is immediately inserted on the target component if it does
31/// not already exist, and the "source" entity is automatically added to the [`RelationshipTarget`] collection (this is done via "component hooks").
32///
33/// A common example of a [`Relationship`] is the parent / child relationship. Bevy ECS includes a canonical form of this via the [`ChildOf`](crate::hierarchy::ChildOf)
34/// [`Relationship`] and the [`Children`](crate::hierarchy::Children) [`RelationshipTarget`].
35///
36/// [`Relationship`] and [`RelationshipTarget`] should always be derived via the [`Component`] trait to ensure the hooks are set up properly.
37///
38/// ## Derive
39///
40/// [`Relationship`] and [`RelationshipTarget`] can only be derived for structs with a single unnamed field, single named field
41/// or for named structs where one field is annotated with `#[relationship]`.
42/// If there are additional fields, they must all implement [`Default`].
43///
44/// [`RelationshipTarget`] also requires that the relationship field is private to prevent direct mutation,
45/// ensuring the correctness of relationships.
46/// ```
47/// # use bevy_ecs::component::Component;
48/// # use bevy_ecs::entity::Entity;
49/// #[derive(Component)]
50/// #[relationship(relationship_target = Children)]
51/// pub struct ChildOf {
52///     #[relationship]
53///     pub parent: Entity,
54///     internal: u8,
55/// };
56///
57/// #[derive(Component)]
58/// #[relationship_target(relationship = ChildOf)]
59/// pub struct Children(Vec<Entity>);
60/// ```
61///
62/// When deriving [`RelationshipTarget`] you can specify the `#[relationship_target(linked_spawn)]` attribute to
63/// automatically despawn entities stored in an entity's [`RelationshipTarget`] when that entity is despawned:
64///
65/// ```
66/// # use bevy_ecs::component::Component;
67/// # use bevy_ecs::entity::Entity;
68/// #[derive(Component)]
69/// #[relationship(relationship_target = Children)]
70/// pub struct ChildOf(pub Entity);
71///
72/// #[derive(Component)]
73/// #[relationship_target(relationship = ChildOf, linked_spawn)]
74/// pub struct Children(Vec<Entity>);
75/// ```
76pub trait Relationship: Component + Sized {
77    /// The [`Component`] added to the "target" entities of this [`Relationship`], which contains the list of all "source"
78    /// entities that relate to the "target".
79    type RelationshipTarget: RelationshipTarget<Relationship = Self>;
80
81    /// Gets the [`Entity`] ID of the related entity.
82    fn get(&self) -> Entity;
83
84    /// Creates this [`Relationship`] from the given `entity`.
85    fn from(entity: Entity) -> Self;
86
87    /// Changes the current [`Entity`] ID of the entity containing the [`RelationshipTarget`] to another one.
88    ///
89    /// This is useful for updating the relationship without overwriting other fields stored in `Self`.
90    ///
91    /// # Warning
92    ///
93    /// This should generally not be called by user code, as modifying the related entity could invalidate the
94    /// relationship. If this method is used, then the hooks [`on_replace`](Relationship::on_replace) have to
95    /// run before and [`on_insert`](Relationship::on_insert) after it.
96    /// This happens automatically when this method is called with [`EntityWorldMut::modify_component`].
97    ///
98    /// Prefer to use regular means of insertions when possible.
99    fn set_risky(&mut self, entity: Entity);
100
101    /// The `on_insert` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
102    fn on_insert(
103        mut world: DeferredWorld,
104        HookContext {
105            entity,
106            caller,
107            relationship_hook_mode,
108            ..
109        }: HookContext,
110    ) {
111        match relationship_hook_mode {
112            RelationshipHookMode::Run => {}
113            RelationshipHookMode::Skip => return,
114            RelationshipHookMode::RunIfNotLinked => {
115                if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
116                    return;
117                }
118            }
119        }
120        let target_entity = world.entity(entity).get::<Self>().unwrap().get();
121        if target_entity == entity {
122            warn!(
123                "{}The {}({target_entity:?}) relationship on entity {entity:?} points to itself. The invalid {} relationship has been removed.",
124                caller.map(|location|format!("{location}: ")).unwrap_or_default(),
125                DebugName::type_name::<Self>(),
126                DebugName::type_name::<Self>()
127            );
128            world.commands().entity(entity).remove::<Self>();
129            return;
130        }
131        // For one-to-one relationships, remove existing relationship before adding new one
132        let current_source_to_remove = world
133            .get_entity(target_entity)
134            .ok()
135            .and_then(|target_entity_ref| target_entity_ref.get::<Self::RelationshipTarget>())
136            .and_then(|relationship_target| {
137                relationship_target
138                    .collection()
139                    .source_to_remove_before_add()
140            });
141
142        if let Some(current_source) = current_source_to_remove {
143            world.commands().entity(current_source).try_remove::<Self>();
144        }
145
146        if let Ok(mut entity_commands) = world.commands().get_entity(target_entity) {
147            // Deferring is necessary for batch mode
148            entity_commands
149                .entry::<Self::RelationshipTarget>()
150                .and_modify(move |mut relationship_target| {
151                    relationship_target.collection_mut_risky().add(entity);
152                })
153                .or_insert_with(move || {
154                    let mut target = Self::RelationshipTarget::with_capacity(1);
155                    target.collection_mut_risky().add(entity);
156                    target
157                });
158        } else {
159            warn!(
160                "{}The {}({target_entity:?}) relationship on entity {entity:?} relates to an entity that does not exist. The invalid {} relationship has been removed.",
161                caller.map(|location|format!("{location}: ")).unwrap_or_default(),
162                DebugName::type_name::<Self>(),
163                DebugName::type_name::<Self>()
164            );
165            world.commands().entity(entity).remove::<Self>();
166        }
167    }
168
169    /// The `on_replace` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
170    // note: think of this as "on_drop"
171    fn on_replace(
172        mut world: DeferredWorld,
173        HookContext {
174            entity,
175            relationship_hook_mode,
176            ..
177        }: HookContext,
178    ) {
179        match relationship_hook_mode {
180            RelationshipHookMode::Run => {}
181            RelationshipHookMode::Skip => return,
182            RelationshipHookMode::RunIfNotLinked => {
183                if <Self::RelationshipTarget as RelationshipTarget>::LINKED_SPAWN {
184                    return;
185                }
186            }
187        }
188        let target_entity = world.entity(entity).get::<Self>().unwrap().get();
189        if let Ok(mut target_entity_mut) = world.get_entity_mut(target_entity) {
190            if let Some(mut relationship_target) =
191                target_entity_mut.get_mut::<Self::RelationshipTarget>()
192            {
193                relationship_target.collection_mut_risky().remove(entity);
194                if relationship_target.len() == 0 {
195                    let command = |mut entity: EntityWorldMut| {
196                        // this "remove" operation must check emptiness because in the event that an identical
197                        // relationship is inserted on top, this despawn would result in the removal of that identical
198                        // relationship ... not what we want!
199                        if entity
200                            .get::<Self::RelationshipTarget>()
201                            .is_some_and(RelationshipTarget::is_empty)
202                        {
203                            entity.remove::<Self::RelationshipTarget>();
204                        }
205                    };
206
207                    world
208                        .commands()
209                        .queue_silenced(command.with_entity(target_entity));
210                }
211            }
212        }
213    }
214}
215
216/// The iterator type for the source entities in a [`RelationshipTarget`] collection,
217/// as defined in the [`RelationshipSourceCollection`] trait.
218pub type SourceIter<'w, R> =
219    <<R as RelationshipTarget>::Collection as RelationshipSourceCollection>::SourceIter<'w>;
220
221/// A [`Component`] containing the collection of entities that relate to this [`Entity`] via the associated `Relationship` type.
222/// See the [`Relationship`] documentation for more information.
223pub trait RelationshipTarget: Component<Mutability = Mutable> + Sized {
224    /// If this is true, when despawning or cloning (when [linked cloning is enabled](crate::entity::EntityClonerBuilder::linked_cloning)), the related entities targeting this entity will also be despawned or cloned.
225    ///
226    /// For example, this is set to `true` for Bevy's built-in parent-child relation, defined by [`ChildOf`](crate::prelude::ChildOf) and [`Children`](crate::prelude::Children).
227    /// This means that when a parent is despawned, any children targeting that parent are also despawned (and the same applies to cloning).
228    ///
229    /// To get around this behavior, you can first break the relationship between entities, and *then* despawn or clone.
230    /// This defaults to false when derived.
231    const LINKED_SPAWN: bool;
232    /// The [`Relationship`] that populates this [`RelationshipTarget`] collection.
233    type Relationship: Relationship<RelationshipTarget = Self>;
234    /// The collection type that stores the "source" entities for this [`RelationshipTarget`] component.
235    ///
236    /// Check the list of types which implement [`RelationshipSourceCollection`] for the data structures that can be used inside of your component.
237    /// If you need a new collection type, you can implement the [`RelationshipSourceCollection`] trait
238    /// for a type you own which wraps the collection you want to use (to avoid the orphan rule),
239    /// or open an issue on the Bevy repository to request first-party support for your collection type.
240    type Collection: RelationshipSourceCollection;
241
242    /// Returns a reference to the stored [`RelationshipTarget::Collection`].
243    fn collection(&self) -> &Self::Collection;
244    /// Returns a mutable reference to the stored [`RelationshipTarget::Collection`].
245    ///
246    /// # Warning
247    /// This should generally not be called by user code, as modifying the internal collection could invalidate the relationship.
248    /// The collection should not contain duplicates.
249    fn collection_mut_risky(&mut self) -> &mut Self::Collection;
250
251    /// Creates a new [`RelationshipTarget`] from the given [`RelationshipTarget::Collection`].
252    ///
253    /// # Warning
254    /// This should generally not be called by user code, as constructing the internal collection could invalidate the relationship.
255    /// The collection should not contain duplicates.
256    fn from_collection_risky(collection: Self::Collection) -> Self;
257
258    /// The `on_replace` component hook that maintains the [`Relationship`] / [`RelationshipTarget`] connection.
259    // note: think of this as "on_drop"
260    fn on_replace(
261        mut world: DeferredWorld,
262        HookContext {
263            entity,
264            relationship_hook_mode,
265            ..
266        }: HookContext,
267    ) {
268        match relationship_hook_mode {
269            RelationshipHookMode::Run => {}
270            // For RelationshipTarget we don't want to run this hook even if it isn't linked, but for Relationship we do.
271            RelationshipHookMode::Skip | RelationshipHookMode::RunIfNotLinked => return,
272        }
273        let (entities, mut commands) = world.entities_and_commands();
274        let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
275        for source_entity in relationship_target.iter() {
276            commands
277                .entity(source_entity)
278                .try_remove::<Self::Relationship>();
279        }
280    }
281
282    /// The `on_despawn` component hook that despawns entities stored in an entity's [`RelationshipTarget`] when
283    /// that entity is despawned.
284    // note: think of this as "on_drop"
285    fn on_despawn(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
286        let (entities, mut commands) = world.entities_and_commands();
287        let relationship_target = entities.get(entity).unwrap().get::<Self>().unwrap();
288        for source_entity in relationship_target.iter() {
289            commands.entity(source_entity).try_despawn();
290        }
291    }
292
293    /// Creates this [`RelationshipTarget`] with the given pre-allocated entity capacity.
294    fn with_capacity(capacity: usize) -> Self {
295        let collection =
296            <Self::Collection as RelationshipSourceCollection>::with_capacity(capacity);
297        Self::from_collection_risky(collection)
298    }
299
300    /// Iterates the entities stored in this collection.
301    #[inline]
302    fn iter(&self) -> SourceIter<'_, Self> {
303        self.collection().iter()
304    }
305
306    /// Returns the number of entities in this collection.
307    #[inline]
308    fn len(&self) -> usize {
309        self.collection().len()
310    }
311
312    /// Returns true if this entity collection is empty.
313    #[inline]
314    fn is_empty(&self) -> bool {
315        self.collection().is_empty()
316    }
317}
318
319/// The "clone behavior" for [`RelationshipTarget`]. The [`RelationshipTarget`] will be populated with the proper components
320/// when the corresponding [`Relationship`] sources of truth are inserted. Cloning the actual entities
321/// in the original [`RelationshipTarget`] would result in duplicates, so we don't do that!
322///
323/// This will also queue up clones of the relationship sources if the [`EntityCloner`](crate::entity::EntityCloner) is configured
324/// to spawn recursively.
325pub fn clone_relationship_target<T: RelationshipTarget>(
326    component: &T,
327    cloned: &mut T,
328    context: &mut ComponentCloneCtx,
329) {
330    if context.linked_cloning() && T::LINKED_SPAWN {
331        let collection = cloned.collection_mut_risky();
332        for entity in component.iter() {
333            collection.add(entity);
334            context.queue_entity_clone(entity);
335        }
336    } else if context.moving() {
337        let target = context.target();
338        let collection = cloned.collection_mut_risky();
339        for entity in component.iter() {
340            collection.add(entity);
341            context.queue_deferred(move |world, _mapper| {
342                // We don't want relationships hooks to run because we are manually constructing the collection here
343                _ = DeferredWorld::from(world)
344                    .modify_component_with_relationship_hook_mode::<T::Relationship, ()>(
345                        entity,
346                        RelationshipHookMode::Skip,
347                        |r| r.set_risky(target),
348                    );
349            });
350        }
351    }
352}
353
354/// Configures the conditions under which the Relationship insert/replace hooks will be run.
355#[derive(Copy, Clone, Debug)]
356pub enum RelationshipHookMode {
357    /// Relationship insert/replace hooks will always run
358    Run,
359    /// Relationship insert/replace hooks will run if [`RelationshipTarget::LINKED_SPAWN`] is false
360    RunIfNotLinked,
361    /// Relationship insert/replace hooks will always be skipped
362    Skip,
363}
364
365/// Wrapper for components clone specialization using autoderef.
366#[doc(hidden)]
367pub struct RelationshipCloneBehaviorSpecialization<T>(PhantomData<T>);
368
369impl<T> Default for RelationshipCloneBehaviorSpecialization<T> {
370    fn default() -> Self {
371        Self(PhantomData)
372    }
373}
374
375/// Base trait for relationship clone specialization using autoderef.
376#[doc(hidden)]
377pub trait RelationshipCloneBehaviorBase {
378    fn default_clone_behavior(&self) -> ComponentCloneBehavior;
379}
380
381impl<C> RelationshipCloneBehaviorBase for RelationshipCloneBehaviorSpecialization<C> {
382    fn default_clone_behavior(&self) -> ComponentCloneBehavior {
383        // Relationships currently must have `Clone`/`Reflect`-based handler for cloning/moving logic to properly work.
384        ComponentCloneBehavior::Ignore
385    }
386}
387
388/// Specialized trait for relationship clone specialization using autoderef.
389#[doc(hidden)]
390pub trait RelationshipCloneBehaviorViaReflect {
391    fn default_clone_behavior(&self) -> ComponentCloneBehavior;
392}
393
394#[cfg(feature = "bevy_reflect")]
395impl<C: Relationship + bevy_reflect::Reflect> RelationshipCloneBehaviorViaReflect
396    for &RelationshipCloneBehaviorSpecialization<C>
397{
398    fn default_clone_behavior(&self) -> ComponentCloneBehavior {
399        ComponentCloneBehavior::reflect()
400    }
401}
402
403/// Specialized trait for relationship clone specialization using autoderef.
404#[doc(hidden)]
405pub trait RelationshipCloneBehaviorViaClone {
406    fn default_clone_behavior(&self) -> ComponentCloneBehavior;
407}
408
409impl<C: Relationship + Clone> RelationshipCloneBehaviorViaClone
410    for &&RelationshipCloneBehaviorSpecialization<C>
411{
412    fn default_clone_behavior(&self) -> ComponentCloneBehavior {
413        ComponentCloneBehavior::clone::<C>()
414    }
415}
416
417/// Specialized trait for relationship target clone specialization using autoderef.
418#[doc(hidden)]
419pub trait RelationshipTargetCloneBehaviorViaReflect {
420    fn default_clone_behavior(&self) -> ComponentCloneBehavior;
421}
422
423#[cfg(feature = "bevy_reflect")]
424impl<C: RelationshipTarget + bevy_reflect::Reflect + bevy_reflect::TypePath>
425    RelationshipTargetCloneBehaviorViaReflect for &&&RelationshipCloneBehaviorSpecialization<C>
426{
427    fn default_clone_behavior(&self) -> ComponentCloneBehavior {
428        ComponentCloneBehavior::Custom(|source, context| {
429            if let Some(component) = source.read::<C>()
430                && let Ok(mut cloned) = component.reflect_clone_and_take::<C>()
431            {
432                cloned.collection_mut_risky().clear();
433                clone_relationship_target(component, &mut cloned, context);
434                context.write_target_component(cloned);
435            }
436        })
437    }
438}
439
440/// Specialized trait for relationship target clone specialization using autoderef.
441#[doc(hidden)]
442pub trait RelationshipTargetCloneBehaviorViaClone {
443    fn default_clone_behavior(&self) -> ComponentCloneBehavior;
444}
445
446impl<C: RelationshipTarget + Clone> RelationshipTargetCloneBehaviorViaClone
447    for &&&&RelationshipCloneBehaviorSpecialization<C>
448{
449    fn default_clone_behavior(&self) -> ComponentCloneBehavior {
450        ComponentCloneBehavior::Custom(|source, context| {
451            if let Some(component) = source.read::<C>() {
452                let mut cloned = component.clone();
453                cloned.collection_mut_risky().clear();
454                clone_relationship_target(component, &mut cloned, context);
455                context.write_target_component(cloned);
456            }
457        })
458    }
459}
460
461/// We know there's no additional data on Children, so this handler is an optimization to avoid cloning the entire Collection.
462#[doc(hidden)]
463pub trait RelationshipTargetCloneBehaviorHierarchy {
464    fn default_clone_behavior(&self) -> ComponentCloneBehavior;
465}
466
467impl RelationshipTargetCloneBehaviorHierarchy
468    for &&&&&RelationshipCloneBehaviorSpecialization<crate::hierarchy::Children>
469{
470    fn default_clone_behavior(&self) -> ComponentCloneBehavior {
471        ComponentCloneBehavior::Custom(|source, context| {
472            if let Some(component) = source.read::<crate::hierarchy::Children>() {
473                let mut cloned = crate::hierarchy::Children::with_capacity(component.len());
474                clone_relationship_target(component, &mut cloned, context);
475                context.write_target_component(cloned);
476            }
477        })
478    }
479}
480
481#[cfg(test)]
482mod tests {
483    use core::marker::PhantomData;
484
485    use crate::prelude::{ChildOf, Children};
486    use crate::world::World;
487    use crate::{component::Component, entity::Entity};
488    use alloc::vec::Vec;
489
490    #[test]
491    fn custom_relationship() {
492        #[derive(Component)]
493        #[relationship(relationship_target = LikedBy)]
494        struct Likes(pub Entity);
495
496        #[derive(Component)]
497        #[relationship_target(relationship = Likes)]
498        struct LikedBy(Vec<Entity>);
499
500        let mut world = World::new();
501        let a = world.spawn_empty().id();
502        let b = world.spawn(Likes(a)).id();
503        let c = world.spawn(Likes(a)).id();
504        assert_eq!(world.entity(a).get::<LikedBy>().unwrap().0, &[b, c]);
505    }
506
507    #[test]
508    fn self_relationship_fails() {
509        #[derive(Component)]
510        #[relationship(relationship_target = RelTarget)]
511        struct Rel(Entity);
512
513        #[derive(Component)]
514        #[relationship_target(relationship = Rel)]
515        struct RelTarget(Vec<Entity>);
516
517        let mut world = World::new();
518        let a = world.spawn_empty().id();
519        world.entity_mut(a).insert(Rel(a));
520        assert!(!world.entity(a).contains::<Rel>());
521        assert!(!world.entity(a).contains::<RelTarget>());
522    }
523
524    #[test]
525    fn relationship_with_missing_target_fails() {
526        #[derive(Component)]
527        #[relationship(relationship_target = RelTarget)]
528        struct Rel(Entity);
529
530        #[derive(Component)]
531        #[relationship_target(relationship = Rel)]
532        struct RelTarget(Vec<Entity>);
533
534        let mut world = World::new();
535        let a = world.spawn_empty().id();
536        world.despawn(a);
537        let b = world.spawn(Rel(a)).id();
538        assert!(!world.entity(b).contains::<Rel>());
539        assert!(!world.entity(b).contains::<RelTarget>());
540    }
541
542    #[test]
543    fn relationship_with_multiple_non_target_fields_compiles() {
544        #[expect(
545            dead_code,
546            reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
547        )]
548        #[derive(Component)]
549        #[relationship(relationship_target=Target)]
550        struct Source {
551            #[relationship]
552            target: Entity,
553            foo: u8,
554            bar: u8,
555        }
556
557        #[expect(
558            dead_code,
559            reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
560        )]
561        #[derive(Component)]
562        #[relationship_target(relationship=Source)]
563        struct Target(Vec<Entity>);
564
565        // No assert necessary, looking to make sure compilation works with the macros
566    }
567    #[test]
568    fn relationship_target_with_multiple_non_target_fields_compiles() {
569        #[expect(
570            dead_code,
571            reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
572        )]
573        #[derive(Component)]
574        #[relationship(relationship_target=Target)]
575        struct Source(Entity);
576
577        #[expect(
578            dead_code,
579            reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
580        )]
581        #[derive(Component)]
582        #[relationship_target(relationship=Source)]
583        struct Target {
584            #[relationship]
585            target: Vec<Entity>,
586            foo: u8,
587            bar: u8,
588        }
589
590        // No assert necessary, looking to make sure compilation works with the macros
591    }
592
593    #[test]
594    fn relationship_with_multiple_unnamed_non_target_fields_compiles() {
595        #[expect(
596            dead_code,
597            reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
598        )]
599        #[derive(Component)]
600        #[relationship(relationship_target=Target<T>)]
601        struct Source<T: Send + Sync + 'static>(#[relationship] Entity, PhantomData<T>);
602
603        #[expect(
604            dead_code,
605            reason = "This struct is used as a compilation test to test the derive macros, and as such is intentionally never constructed."
606        )]
607        #[derive(Component)]
608        #[relationship_target(relationship=Source<T>)]
609        struct Target<T: Send + Sync + 'static>(#[relationship] Vec<Entity>, PhantomData<T>);
610
611        // No assert necessary, looking to make sure compilation works with the macros
612    }
613
614    #[test]
615    fn parent_child_relationship_with_custom_relationship() {
616        #[derive(Component)]
617        #[relationship(relationship_target = RelTarget)]
618        struct Rel(Entity);
619
620        #[derive(Component)]
621        #[relationship_target(relationship = Rel)]
622        struct RelTarget(Entity);
623
624        let mut world = World::new();
625
626        // Rel on Parent
627        // Despawn Parent
628        let mut commands = world.commands();
629        let child = commands.spawn_empty().id();
630        let parent = commands.spawn(Rel(child)).add_child(child).id();
631        commands.entity(parent).despawn();
632        world.flush();
633
634        assert!(world.get_entity(child).is_err());
635        assert!(world.get_entity(parent).is_err());
636
637        // Rel on Parent
638        // Despawn Child
639        let mut commands = world.commands();
640        let child = commands.spawn_empty().id();
641        let parent = commands.spawn(Rel(child)).add_child(child).id();
642        commands.entity(child).despawn();
643        world.flush();
644
645        assert!(world.get_entity(child).is_err());
646        assert!(!world.entity(parent).contains::<Rel>());
647
648        // Rel on Child
649        // Despawn Parent
650        let mut commands = world.commands();
651        let parent = commands.spawn_empty().id();
652        let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
653        commands.entity(parent).despawn();
654        world.flush();
655
656        assert!(world.get_entity(child).is_err());
657        assert!(world.get_entity(parent).is_err());
658
659        // Rel on Child
660        // Despawn Child
661        let mut commands = world.commands();
662        let parent = commands.spawn_empty().id();
663        let child = commands.spawn((ChildOf(parent), Rel(parent))).id();
664        commands.entity(child).despawn();
665        world.flush();
666
667        assert!(world.get_entity(child).is_err());
668        assert!(!world.entity(parent).contains::<RelTarget>());
669    }
670
671    #[test]
672    fn spawn_batch_with_relationship() {
673        let mut world = World::new();
674        let parent = world.spawn_empty().id();
675        let children = world
676            .spawn_batch((0..10).map(|_| ChildOf(parent)))
677            .collect::<Vec<_>>();
678
679        for &child in &children {
680            assert!(world
681                .get::<ChildOf>(child)
682                .is_some_and(|child_of| child_of.parent() == parent));
683        }
684        assert!(world
685            .get::<Children>(parent)
686            .is_some_and(|children| children.len() == 10));
687    }
688
689    #[test]
690    fn insert_batch_with_relationship() {
691        let mut world = World::new();
692        let parent = world.spawn_empty().id();
693        let child = world.spawn_empty().id();
694        world.insert_batch([(child, ChildOf(parent))]);
695        world.flush();
696
697        assert!(world.get::<ChildOf>(child).is_some());
698        assert!(world.get::<Children>(parent).is_some());
699    }
700}