pub mod component_frag;
pub mod entity_frag;
pub mod join_iter;

mod impls;

pub trait AsQuery<'a, T> {
    type Q;

    fn as_query(&'a self) -> Self::Q;
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::prelude::*;
    use test_db::{Db as World, Query};

    struct C1;
    struct C2(pub i32);
    struct C3;

    db!(
        import_root crate
        module test_db
        components
        [
            C1,
            C2,
            C3,
        ]
    );

    #[test]
    fn test_as_query_frag() {
        // test if compiles
        //

        let mut db = World::new(128);

        let id = db.spawn_entity();
        db.insert(id, C1);
        db.insert(id, C2(42));

        let _frag: ComponentFrag<C2> = <World as AsQuery<C2>>::as_query(&db);

        let _tipli = <World as AsQuery<(C1,)>>::as_query(&db);
        let _tipli = <World as AsQuery<(C1, C2)>>::as_query(&db);
        let _tipli = <World as AsQuery<(C1, C2, C3)>>::as_query(&db);
        let _tipli = <World as AsQuery<(C3, C1)>>::as_query(&db);
    }

    #[test]
    fn test_queries() {
        fn sys_c1(q: Query<C1>) {
            // exactly 1 item...
            let mut hit = false;

            for (_idx, C1) in q.into_inner().iter() {
                assert!(!hit, "expected 1 item");
                hit = true;
            }
            assert!(hit, "expected 1 item");
        }

        fn sys_c1_c2(_q: Query<(C1, C2)>) {}
        fn sys_c1_c3_c2(_q: Query<(C1, C3, C2)>) {}
        fn sys_c3_c1(_q: Query<(C3, C1)>) {}

        let mut w = World::new(128);

        {
            let id = w.spawn_entity();
            w.insert(id, C1);
            w.insert(id, C2(42));
        }

        sys_c1(Query::new(&w));
        sys_c1_c2(Query::new(&w));
        sys_c1_c3_c2(Query::new(&w));
        sys_c3_c1(Query::new(&w));
    }
}
