Skip to main content

diesel/sqlite/connection/
update_hook.rs

1//! Types for the SQLite data change notification hook.
2//!
3//! See [`SqliteConnection::on_update`](super::SqliteConnection::on_update) for usage.
4
5#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
6extern crate libsqlite3_sys as ffi;
7
8#[cfg(all(target_family = "wasm", target_os = "unknown"))]
9use sqlite_wasm_rs as ffi;
10
11use crate::query_source::NamedTable;
12use alloc::boxed::Box;
13use alloc::vec::Vec;
14
15#[doc =
r" A bitmask of SQLite change operations used for filtering which events"]
#[doc = r" a hook should receive."]
#[doc = r""]
#[doc = r" Combine masks with `|` (bitwise OR):"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" # use diesel::sqlite::SqliteChangeOps;"]
#[doc =
r" let insert_or_delete = SqliteChangeOps::INSERT | SqliteChangeOps::DELETE;"]
#[doc = r" assert!(insert_or_delete.contains(SqliteChangeOps::INSERT));"]
#[doc = r" assert!(!insert_or_delete.contains(SqliteChangeOps::UPDATE));"]
#[doc = r" ```"]
pub struct SqliteChangeOps(<SqliteChangeOps as
    ::bitflags::__private::PublicFlags>::Internal);
#[automatically_derived]
impl ::core::fmt::Debug for SqliteChangeOps {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
            "SqliteChangeOps", &&self.0)
    }
}
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for SqliteChangeOps { }
#[automatically_derived]
impl ::core::clone::Clone for SqliteChangeOps {
    #[inline]
    fn clone(&self) -> SqliteChangeOps {
        let _:
                ::core::clone::AssertParamIsClone<<SqliteChangeOps as
                ::bitflags::__private::PublicFlags>::Internal>;
        *self
    }
}
#[automatically_derived]
impl ::core::marker::Copy for SqliteChangeOps { }
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for SqliteChangeOps { }
#[automatically_derived]
impl ::core::cmp::PartialEq for SqliteChangeOps {
    #[inline]
    fn eq(&self, other: &SqliteChangeOps) -> bool { self.0 == other.0 }
}
#[automatically_derived]
impl ::core::cmp::Eq for SqliteChangeOps {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _:
                ::core::cmp::AssertParamIsEq<<SqliteChangeOps as
                ::bitflags::__private::PublicFlags>::Internal>;
    }
}
#[automatically_derived]
impl ::core::hash::Hash for SqliteChangeOps {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.0, state)
    }
}
#[allow(dead_code, deprecated, unused_doc_comments, unused_attributes,
unused_mut, unused_imports, non_upper_case_globals, clippy :: min_ident_chars,
clippy :: assign_op_pattern, clippy :: indexing_slicing, clippy ::
same_name_method, clippy :: iter_without_into_iter,)]
const _: () =
    {
        #[repr(transparent)]
        pub struct InternalBitFlags(u8);
        #[automatically_derived]
        #[doc(hidden)]
        unsafe impl ::core::clone::TrivialClone for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::clone::Clone for InternalBitFlags {
            #[inline]
            fn clone(&self) -> InternalBitFlags {
                let _: ::core::clone::AssertParamIsClone<u8>;
                *self
            }
        }
        #[automatically_derived]
        impl ::core::marker::Copy for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::marker::StructuralPartialEq for InternalBitFlags { }
        #[automatically_derived]
        impl ::core::cmp::PartialEq for InternalBitFlags {
            #[inline]
            fn eq(&self, other: &InternalBitFlags) -> bool {
                self.0 == other.0
            }
        }
        #[automatically_derived]
        impl ::core::cmp::Eq for InternalBitFlags {
            #[inline]
            #[doc(hidden)]
            #[coverage(off)]
            fn assert_fields_are_eq(&self) {
                let _: ::core::cmp::AssertParamIsEq<u8>;
            }
        }
        #[automatically_derived]
        impl ::core::cmp::PartialOrd for InternalBitFlags {
            #[inline]
            fn partial_cmp(&self, other: &InternalBitFlags)
                -> ::core::option::Option<::core::cmp::Ordering> {
                ::core::option::Option::Some(::core::cmp::Ord::cmp(self,
                        other))
            }
        }
        #[automatically_derived]
        impl ::core::cmp::Ord for InternalBitFlags {
            #[inline]
            fn cmp(&self, other: &InternalBitFlags) -> ::core::cmp::Ordering {
                ::core::cmp::Ord::cmp(&self.0, &other.0)
            }
        }
        #[automatically_derived]
        impl ::core::hash::Hash for InternalBitFlags {
            #[inline]
            fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
                ::core::hash::Hash::hash(&self.0, state)
            }
        }
        impl SqliteChangeOps {
            #[doc = r" Match INSERT operations."]
            pub const INSERT: Self = Self::from_bits_retain(1);
            #[doc = r" Match UPDATE operations."]
            pub const UPDATE: Self = Self::from_bits_retain(2);
            #[doc = r" Match DELETE operations."]
            pub const DELETE: Self = Self::from_bits_retain(4);
            #[doc = r" Match unknown or future operation codes."]
            pub const UNKNOWN: Self = Self::from_bits_retain(8);
            #[doc =
            r" Match all row-change operations (INSERT, UPDATE, DELETE, and UNKNOWN)."]
            #[doc = r""]
            #[doc =
            r" `UNKNOWN` is included deliberately: if a future SQLite version emits"]
            #[doc =
            r" an operation code diesel does not recognize, a hook registered with"]
            #[doc =
            r" `ALL` still fires (with [`SqliteChangeOp::Unknown`] carrying the raw"]
            #[doc = r" code) rather than silently dropping the change."]
            pub const ALL: Self =
                Self::from_bits_retain(Self::INSERT.bits() |
                                Self::UPDATE.bits() | Self::DELETE.bits() |
                        Self::UNKNOWN.bits());
        }
        impl ::bitflags::Flags for SqliteChangeOps {
            const FLAGS: &'static [::bitflags::Flag<SqliteChangeOps>] =
                {
                    mod __bitflags_flag_names {
                        use super::*;
                        pub(super) const INSERT: &'static str = "INSERT";
                        pub(super) const UPDATE: &'static str = "UPDATE";
                        pub(super) const DELETE: &'static str = "DELETE";
                        pub(super) const UNKNOWN: &'static str = "UNKNOWN";
                        pub(super) const ALL: &'static str = "ALL";
                    }
                    &[{
                                    ::bitflags::Flag::new(__bitflags_flag_names::INSERT,
                                        SqliteChangeOps::INSERT)
                                },
                                {
                                    ::bitflags::Flag::new(__bitflags_flag_names::UPDATE,
                                        SqliteChangeOps::UPDATE)
                                },
                                {
                                    ::bitflags::Flag::new(__bitflags_flag_names::DELETE,
                                        SqliteChangeOps::DELETE)
                                },
                                {
                                    ::bitflags::Flag::new(__bitflags_flag_names::UNKNOWN,
                                        SqliteChangeOps::UNKNOWN)
                                },
                                {
                                    ::bitflags::Flag::new(__bitflags_flag_names::ALL,
                                        SqliteChangeOps::ALL)
                                }]
                };
            type Bits = u8;
            fn bits(&self) -> u8 { SqliteChangeOps::bits(self) }
            fn from_bits_retain(bits: u8) -> SqliteChangeOps {
                SqliteChangeOps::from_bits_retain(bits)
            }
            fn all_named() -> SqliteChangeOps {
                const ALL_NAMED: u8 =
                    {
                        let mut truncated = <u8 as ::bitflags::Bits>::EMPTY;
                        let mut i = 0;
                        {
                            {
                                let flag =
                                    &<SqliteChangeOps as ::bitflags::Flags>::FLAGS[i];
                                if flag.is_named() {
                                    truncated = truncated | flag.value().bits();
                                }
                                i += 1;
                            }
                        };
                        {
                            {
                                let flag =
                                    &<SqliteChangeOps as ::bitflags::Flags>::FLAGS[i];
                                if flag.is_named() {
                                    truncated = truncated | flag.value().bits();
                                }
                                i += 1;
                            }
                        };
                        {
                            {
                                let flag =
                                    &<SqliteChangeOps as ::bitflags::Flags>::FLAGS[i];
                                if flag.is_named() {
                                    truncated = truncated | flag.value().bits();
                                }
                                i += 1;
                            }
                        };
                        {
                            {
                                let flag =
                                    &<SqliteChangeOps as ::bitflags::Flags>::FLAGS[i];
                                if flag.is_named() {
                                    truncated = truncated | flag.value().bits();
                                }
                                i += 1;
                            }
                        };
                        {
                            {
                                let flag =
                                    &<SqliteChangeOps as ::bitflags::Flags>::FLAGS[i];
                                if flag.is_named() {
                                    truncated = truncated | flag.value().bits();
                                }
                                i += 1;
                            }
                        };
                        let _ = i;
                        truncated
                    };
                SqliteChangeOps::from_bits_retain(ALL_NAMED)
            }
        }
        impl ::bitflags::__private::PublicFlags for SqliteChangeOps {
            type Primitive = u8;
            type Internal = InternalBitFlags;
        }
        impl ::bitflags::__private::core::default::Default for
            InternalBitFlags {
            #[inline]
            fn default() -> Self { InternalBitFlags::empty() }
        }
        impl ::bitflags::__private::core::fmt::Debug for InternalBitFlags {
            fn fmt(&self,
                f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
                -> ::bitflags::__private::core::fmt::Result {
                if self.is_empty() {
                    f.write_fmt(format_args!("{0:#x}",
                            <u8 as ::bitflags::Bits>::EMPTY))
                } else {
                    ::bitflags::__private::core::fmt::Display::fmt(self, f)
                }
            }
        }
        impl ::bitflags::__private::core::fmt::Display for InternalBitFlags {
            fn fmt(&self,
                f: &mut ::bitflags::__private::core::fmt::Formatter<'_>)
                -> ::bitflags::__private::core::fmt::Result {
                ::bitflags::parser::to_writer(&SqliteChangeOps(*self), f)
            }
        }
        impl ::bitflags::__private::core::str::FromStr for InternalBitFlags {
            type Err = ::bitflags::parser::ParseError;
            fn from_str(s: &str)
                ->
                    ::bitflags::__private::core::result::Result<Self,
                    Self::Err> {
                ::bitflags::parser::from_str::<SqliteChangeOps>(s).map(|flags|
                        flags.0)
            }
        }
        impl ::bitflags::__private::core::convert::AsRef<u8> for
            InternalBitFlags {
            fn as_ref(&self) -> &u8 { &self.0 }
        }
        impl ::bitflags::__private::core::convert::From<u8> for
            InternalBitFlags {
            fn from(bits: u8) -> Self { Self::from_bits_retain(bits) }
        }
        impl InternalBitFlags {
            /// Get a flags value with all bits unset.
            #[inline]
            pub const fn empty() -> Self {
                Self(<u8 as ::bitflags::Bits>::EMPTY)
            }
            /// Get a flags value with all known bits set.
            #[inline]
            pub const fn all() -> Self {
                const ALL: InternalBitFlags =
                    {
                        let mut truncated = <u8 as ::bitflags::Bits>::EMPTY;
                        let mut _i = 0;
                        {
                            {
                                truncated |=
                                    <SqliteChangeOps as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <SqliteChangeOps as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <SqliteChangeOps as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <SqliteChangeOps as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        {
                            {
                                truncated |=
                                    <SqliteChangeOps as
                                                    ::bitflags::Flags>::FLAGS[_i].value().bits();
                                _i += 1;
                            }
                        };
                        InternalBitFlags(truncated)
                    };
                ALL
            }
            /// Get the underlying bits value.
            ///
            /// The returned value is exactly the bits set in this flags value.
            #[inline]
            pub const fn bits(&self) -> u8 { self.0 }
            /// Convert from a bits value.
            ///
            /// This method will return `None` if any unknown bits are set.
            #[inline]
            pub const fn from_bits(bits: u8)
                -> ::bitflags::__private::core::option::Option<Self> {
                let truncated = Self::from_bits_truncate(bits).0;
                if truncated == bits {
                    ::bitflags::__private::core::option::Option::Some(Self(bits))
                } else { ::bitflags::__private::core::option::Option::None }
            }
            /// Convert from a bits value, unsetting any unknown bits.
            #[inline]
            pub const fn from_bits_truncate(bits: u8) -> Self {
                Self(bits & Self::all().0)
            }
            /// Convert from a bits value exactly.
            #[inline]
            pub const fn from_bits_retain(bits: u8) -> Self { Self(bits) }
            /// Get a flags value with the bits of a flag with the given name set.
            ///
            /// This method will return `None` if `name` is empty or doesn't
            /// correspond to any named flag.
            #[inline]
            pub fn from_name(name: &str)
                -> ::bitflags::__private::core::option::Option<Self> {
                mod __bitflags_flag_names {
                    use super::*;
                    pub(super) const INSERT: &'static str = "INSERT";
                    pub(super) const UPDATE: &'static str = "UPDATE";
                    pub(super) const DELETE: &'static str = "DELETE";
                    pub(super) const UNKNOWN: &'static str = "UNKNOWN";
                    pub(super) const ALL: &'static str = "ALL";
                }
                {
                    {
                        if name == __bitflags_flag_names::INSERT {
                            return ::bitflags::__private::core::option::Option::Some(Self(SqliteChangeOps::INSERT.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::UPDATE {
                            return ::bitflags::__private::core::option::Option::Some(Self(SqliteChangeOps::UPDATE.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::DELETE {
                            return ::bitflags::__private::core::option::Option::Some(Self(SqliteChangeOps::DELETE.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::UNKNOWN {
                            return ::bitflags::__private::core::option::Option::Some(Self(SqliteChangeOps::UNKNOWN.bits()));
                        }
                    };
                };
                {
                    {
                        if name == __bitflags_flag_names::ALL {
                            return ::bitflags::__private::core::option::Option::Some(Self(SqliteChangeOps::ALL.bits()));
                        }
                    };
                };
                let _ = name;
                ::bitflags::__private::core::option::Option::None
            }
            /// Whether all bits in `self` are unset.
            #[inline]
            pub const fn is_empty(&self) -> bool {
                self.0 == <u8 as ::bitflags::Bits>::EMPTY
            }
            /// Whether all known bits in this flags value are set.
            #[inline]
            pub const fn is_all(&self) -> bool {
                Self::all().0 | self.0 == self.0
            }
            /// Whether any set bits in `other` are also set in `self`.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0 & other.0 != <u8 as ::bitflags::Bits>::EMPTY
            }
            /// Whether all set bits in `other` are also set in `self`.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0 & other.0 == other.0
            }
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            pub fn insert(&mut self, other: Self) {
                *self = Self(self.0).union(other);
            }
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `remove` won't truncate `other`, but the `!` operator will.
            #[inline]
            pub fn remove(&mut self, other: Self) {
                *self = Self(self.0).difference(other);
            }
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            pub fn toggle(&mut self, other: Self) {
                *self = Self(self.0).symmetric_difference(other);
            }
            /// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                if value { self.insert(other); } else { self.remove(other); }
            }
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0 & other.0)
            }
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0 | other.0)
            }
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0 & !other.0)
            }
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0 ^ other.0)
            }
            /// The bitwise negation (`!`) of the bits in `self`, truncating the result.
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self::from_bits_truncate(!self.0)
            }
        }
        impl ::bitflags::__private::core::fmt::Binary for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::Octal for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::LowerHex for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::UpperHex for InternalBitFlags {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::ops::BitOr for InternalBitFlags {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            fn bitor(self, other: InternalBitFlags) -> Self {
                self.union(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for
            InternalBitFlags {
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            fn bitor_assign(&mut self, other: Self) { self.insert(other); }
        }
        impl ::bitflags::__private::core::ops::BitXor for InternalBitFlags {
            type Output = Self;
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitXorAssign for
            InternalBitFlags {
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
        }
        impl ::bitflags::__private::core::ops::BitAnd for InternalBitFlags {
            type Output = Self;
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            fn bitand(self, other: Self) -> Self { self.intersection(other) }
        }
        impl ::bitflags::__private::core::ops::BitAndAssign for
            InternalBitFlags {
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                *self =
                    Self::from_bits_retain(self.bits()).intersection(other);
            }
        }
        impl ::bitflags::__private::core::ops::Sub for InternalBitFlags {
            type Output = Self;
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub(self, other: Self) -> Self { self.difference(other) }
        }
        impl ::bitflags::__private::core::ops::SubAssign for InternalBitFlags
            {
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub_assign(&mut self, other: Self) { self.remove(other); }
        }
        impl ::bitflags::__private::core::ops::Not for InternalBitFlags {
            type Output = Self;
            /// The bitwise negation (`!`) of the bits in `self`, truncating the result.
            #[inline]
            fn not(self) -> Self { self.complement() }
        }
        impl ::bitflags::__private::core::iter::Extend<InternalBitFlags> for
            InternalBitFlags {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(&mut self, iterator: T) {
                for item in iterator { self.insert(item) }
            }
        }
        impl ::bitflags::__private::core::iter::FromIterator<InternalBitFlags>
            for InternalBitFlags {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(iterator: T) -> Self {
                use ::bitflags::__private::core::iter::Extend;
                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }
        impl InternalBitFlags {
            /// Yield a set of contained flags values.
            ///
            /// Each yielded flags value will correspond to a defined named flag. Any unknown bits
            /// will be yielded together as a final flags value.
            #[inline]
            pub const fn iter(&self)
                -> ::bitflags::iter::Iter<SqliteChangeOps> {
                ::bitflags::iter::Iter::__private_const_new(<SqliteChangeOps
                        as ::bitflags::Flags>::FLAGS,
                    SqliteChangeOps::from_bits_retain(self.bits()),
                    SqliteChangeOps::from_bits_retain(self.bits()))
            }
            /// Yield a set of contained named flags values.
            ///
            /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
            /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
            #[inline]
            pub const fn iter_names(&self)
                -> ::bitflags::iter::IterNames<SqliteChangeOps> {
                ::bitflags::iter::IterNames::__private_const_new(<SqliteChangeOps
                        as ::bitflags::Flags>::FLAGS,
                    SqliteChangeOps::from_bits_retain(self.bits()),
                    SqliteChangeOps::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for
            InternalBitFlags {
            type Item = SqliteChangeOps;
            type IntoIter = ::bitflags::iter::Iter<SqliteChangeOps>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
        impl InternalBitFlags {
            /// Returns a mutable reference to the raw value of the flags currently stored.
            #[inline]
            pub fn bits_mut(&mut self) -> &mut u8 { &mut self.0 }
        }
        impl SqliteChangeOps {
            /// Get a flags value with all bits unset.
            #[inline]
            pub const fn empty() -> Self { Self(InternalBitFlags::empty()) }
            /// Get a flags value with all known bits set.
            #[inline]
            pub const fn all() -> Self { Self(InternalBitFlags::all()) }
            /// Get the underlying bits value.
            ///
            /// The returned value is exactly the bits set in this flags value.
            #[inline]
            pub const fn bits(&self) -> u8 { self.0.bits() }
            /// Convert from a bits value.
            ///
            /// This method will return `None` if any unknown bits are set.
            #[inline]
            pub const fn from_bits(bits: u8)
                -> ::bitflags::__private::core::option::Option<Self> {
                match InternalBitFlags::from_bits(bits) {
                    ::bitflags::__private::core::option::Option::Some(bits) =>
                        ::bitflags::__private::core::option::Option::Some(Self(bits)),
                    ::bitflags::__private::core::option::Option::None =>
                        ::bitflags::__private::core::option::Option::None,
                }
            }
            /// Convert from a bits value, unsetting any unknown bits.
            #[inline]
            pub const fn from_bits_truncate(bits: u8) -> Self {
                Self(InternalBitFlags::from_bits_truncate(bits))
            }
            /// Convert from a bits value exactly.
            #[inline]
            pub const fn from_bits_retain(bits: u8) -> Self {
                Self(InternalBitFlags::from_bits_retain(bits))
            }
            /// Get a flags value with the bits of a flag with the given name set.
            ///
            /// This method will return `None` if `name` is empty or doesn't
            /// correspond to any named flag.
            #[inline]
            pub fn from_name(name: &str)
                -> ::bitflags::__private::core::option::Option<Self> {
                match InternalBitFlags::from_name(name) {
                    ::bitflags::__private::core::option::Option::Some(bits) =>
                        ::bitflags::__private::core::option::Option::Some(Self(bits)),
                    ::bitflags::__private::core::option::Option::None =>
                        ::bitflags::__private::core::option::Option::None,
                }
            }
            /// Whether all bits in `self` are unset.
            #[inline]
            pub const fn is_empty(&self) -> bool { self.0.is_empty() }
            /// Whether all known bits in this flags value are set.
            #[inline]
            pub const fn is_all(&self) -> bool { self.0.is_all() }
            /// Whether any set bits in `other` are also set in `self`.
            #[inline]
            pub const fn intersects(&self, other: Self) -> bool {
                self.0.intersects(other.0)
            }
            /// Whether all set bits in `other` are also set in `self`.
            #[inline]
            pub const fn contains(&self, other: Self) -> bool {
                self.0.contains(other.0)
            }
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            pub fn insert(&mut self, other: Self) { self.0.insert(other.0) }
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `remove` won't truncate `other`, but the `!` operator will.
            #[inline]
            pub fn remove(&mut self, other: Self) { self.0.remove(other.0) }
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            pub fn toggle(&mut self, other: Self) { self.0.toggle(other.0) }
            /// Call `insert` when `value` is `true` or `remove` when `value` is `false`.
            #[inline]
            pub fn set(&mut self, other: Self, value: bool) {
                self.0.set(other.0, value)
            }
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn intersection(self, other: Self) -> Self {
                Self(self.0.intersection(other.0))
            }
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn union(self, other: Self) -> Self {
                Self(self.0.union(other.0))
            }
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            #[must_use]
            pub const fn difference(self, other: Self) -> Self {
                Self(self.0.difference(other.0))
            }
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            #[must_use]
            pub const fn symmetric_difference(self, other: Self) -> Self {
                Self(self.0.symmetric_difference(other.0))
            }
            /// The bitwise negation (`!`) of the bits in `self`, truncating the result.
            #[inline]
            #[must_use]
            pub const fn complement(self) -> Self {
                Self(self.0.complement())
            }
        }
        impl ::bitflags::__private::core::fmt::Binary for SqliteChangeOps {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Binary::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::Octal for SqliteChangeOps {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::Octal::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::LowerHex for SqliteChangeOps {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::LowerHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::fmt::UpperHex for SqliteChangeOps {
            fn fmt(&self, f: &mut ::bitflags::__private::core::fmt::Formatter)
                -> ::bitflags::__private::core::fmt::Result {
                let inner = self.0;
                ::bitflags::__private::core::fmt::UpperHex::fmt(&inner, f)
            }
        }
        impl ::bitflags::__private::core::ops::BitOr for SqliteChangeOps {
            type Output = Self;
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            fn bitor(self, other: SqliteChangeOps) -> Self {
                self.union(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitOrAssign for SqliteChangeOps
            {
            /// The bitwise or (`|`) of the bits in `self` and `other`.
            #[inline]
            fn bitor_assign(&mut self, other: Self) { self.insert(other); }
        }
        impl ::bitflags::__private::core::ops::BitXor for SqliteChangeOps {
            type Output = Self;
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            fn bitxor(self, other: Self) -> Self {
                self.symmetric_difference(other)
            }
        }
        impl ::bitflags::__private::core::ops::BitXorAssign for
            SqliteChangeOps {
            /// The bitwise exclusive-or (`^`) of the bits in `self` and `other`.
            #[inline]
            fn bitxor_assign(&mut self, other: Self) { self.toggle(other); }
        }
        impl ::bitflags::__private::core::ops::BitAnd for SqliteChangeOps {
            type Output = Self;
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            fn bitand(self, other: Self) -> Self { self.intersection(other) }
        }
        impl ::bitflags::__private::core::ops::BitAndAssign for
            SqliteChangeOps {
            /// The bitwise and (`&`) of the bits in `self` and `other`.
            #[inline]
            fn bitand_assign(&mut self, other: Self) {
                *self =
                    Self::from_bits_retain(self.bits()).intersection(other);
            }
        }
        impl ::bitflags::__private::core::ops::Sub for SqliteChangeOps {
            type Output = Self;
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub(self, other: Self) -> Self { self.difference(other) }
        }
        impl ::bitflags::__private::core::ops::SubAssign for SqliteChangeOps {
            /// The intersection of `self` with the complement of `other` (`&!`).
            ///
            /// This method is not equivalent to `self & !other` when `other` has unknown bits set.
            /// `difference` won't truncate `other`, but the `!` operator will.
            #[inline]
            fn sub_assign(&mut self, other: Self) { self.remove(other); }
        }
        impl ::bitflags::__private::core::ops::Not for SqliteChangeOps {
            type Output = Self;
            /// The bitwise negation (`!`) of the bits in `self`, truncating the result.
            #[inline]
            fn not(self) -> Self { self.complement() }
        }
        impl ::bitflags::__private::core::iter::Extend<SqliteChangeOps> for
            SqliteChangeOps {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn extend<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(&mut self, iterator: T) {
                for item in iterator { self.insert(item) }
            }
        }
        impl ::bitflags::__private::core::iter::FromIterator<SqliteChangeOps>
            for SqliteChangeOps {
            /// The bitwise or (`|`) of the bits in each flags value.
            fn from_iter<T: ::bitflags::__private::core::iter::IntoIterator<Item
                = Self>>(iterator: T) -> Self {
                use ::bitflags::__private::core::iter::Extend;
                let mut result = Self::empty();
                result.extend(iterator);
                result
            }
        }
        impl SqliteChangeOps {
            /// Yield a set of contained flags values.
            ///
            /// Each yielded flags value will correspond to a defined named flag. Any unknown bits
            /// will be yielded together as a final flags value.
            #[inline]
            pub const fn iter(&self)
                -> ::bitflags::iter::Iter<SqliteChangeOps> {
                ::bitflags::iter::Iter::__private_const_new(<SqliteChangeOps
                        as ::bitflags::Flags>::FLAGS,
                    SqliteChangeOps::from_bits_retain(self.bits()),
                    SqliteChangeOps::from_bits_retain(self.bits()))
            }
            /// Yield a set of contained named flags values.
            ///
            /// This method is like [`iter`](#method.iter), except only yields bits in contained named flags.
            /// Any unknown bits, or bits not corresponding to a contained flag will not be yielded.
            #[inline]
            pub const fn iter_names(&self)
                -> ::bitflags::iter::IterNames<SqliteChangeOps> {
                ::bitflags::iter::IterNames::__private_const_new(<SqliteChangeOps
                        as ::bitflags::Flags>::FLAGS,
                    SqliteChangeOps::from_bits_retain(self.bits()),
                    SqliteChangeOps::from_bits_retain(self.bits()))
            }
        }
        impl ::bitflags::__private::core::iter::IntoIterator for
            SqliteChangeOps {
            type Item = SqliteChangeOps;
            type IntoIter = ::bitflags::iter::Iter<SqliteChangeOps>;
            fn into_iter(self) -> Self::IntoIter { self.iter() }
        }
    };bitflags::bitflags! {
16    /// A bitmask of SQLite change operations used for filtering which events
17    /// a hook should receive.
18    ///
19    /// Combine masks with `|` (bitwise OR):
20    ///
21    /// ```rust
22    /// # use diesel::sqlite::SqliteChangeOps;
23    /// let insert_or_delete = SqliteChangeOps::INSERT | SqliteChangeOps::DELETE;
24    /// assert!(insert_or_delete.contains(SqliteChangeOps::INSERT));
25    /// assert!(!insert_or_delete.contains(SqliteChangeOps::UPDATE));
26    /// ```
27    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28    pub struct SqliteChangeOps: u8 {
29        /// Match INSERT operations.
30        const INSERT = 1;
31        /// Match UPDATE operations.
32        const UPDATE = 2;
33        /// Match DELETE operations.
34        const DELETE = 4;
35        /// Match unknown or future operation codes.
36        const UNKNOWN = 8;
37        /// Match all row-change operations (INSERT, UPDATE, DELETE, and UNKNOWN).
38        ///
39        /// `UNKNOWN` is included deliberately: if a future SQLite version emits
40        /// an operation code diesel does not recognize, a hook registered with
41        /// `ALL` still fires (with [`SqliteChangeOp::Unknown`] carrying the raw
42        /// code) rather than silently dropping the change.
43        const ALL =
44            Self::INSERT.bits() | Self::UPDATE.bits() | Self::DELETE.bits() | Self::UNKNOWN.bits();
45    }
46}
47
48impl SqliteChangeOps {
49    /// Checks whether this mask includes the given [`SqliteChangeOp`].
50    pub(crate) fn matches_op(self, op: SqliteChangeOp) -> bool {
51        self.contains(op.to_ops())
52    }
53}
54
55/// Identifies which kind of row change occurred.
56///
57/// Returned as part of [`SqliteChangeEvent`] to the callback registered via
58/// [`on_update`](super::SqliteConnection::on_update).
59#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SqliteChangeOp {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            SqliteChangeOp::Insert =>
                ::core::fmt::Formatter::write_str(f, "Insert"),
            SqliteChangeOp::Update =>
                ::core::fmt::Formatter::write_str(f, "Update"),
            SqliteChangeOp::Delete =>
                ::core::fmt::Formatter::write_str(f, "Delete"),
            SqliteChangeOp::Unknown(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Unknown", &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SqliteChangeOp {
    #[inline]
    fn clone(&self) -> SqliteChangeOp {
        let _: ::core::clone::AssertParamIsClone<i32>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for SqliteChangeOp { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for SqliteChangeOp {
    #[inline]
    fn eq(&self, other: &SqliteChangeOp) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (SqliteChangeOp::Unknown(__self_0),
                    SqliteChangeOp::Unknown(__arg1_0)) => __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for SqliteChangeOp {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<i32>;
    }
}Eq)]
60#[non_exhaustive]
61pub enum SqliteChangeOp {
62    /// A row was inserted.
63    Insert,
64    /// A row was updated.
65    Update,
66    /// A row was deleted.
67    Delete,
68    /// An operation code this version of diesel does not recognize, for example
69    /// one added by a future SQLite version. The inner value is the raw FFI code.
70    Unknown(i32),
71}
72
73impl SqliteChangeOp {
74    /// Converts a raw FFI operation code to the corresponding enum variant.
75    pub(crate) fn from_ffi(code: i32) -> Self {
76        #[allow(non_upper_case_globals)]
77        match code {
78            ffi::SQLITE_INSERT => SqliteChangeOp::Insert,
79            ffi::SQLITE_UPDATE => SqliteChangeOp::Update,
80            ffi::SQLITE_DELETE => SqliteChangeOp::Delete,
81            other => SqliteChangeOp::Unknown(other),
82        }
83    }
84
85    /// Converts this single operation to the corresponding [`SqliteChangeOps`]
86    /// bitmask.
87    pub(crate) fn to_ops(self) -> SqliteChangeOps {
88        match self {
89            SqliteChangeOp::Insert => SqliteChangeOps::INSERT,
90            SqliteChangeOp::Update => SqliteChangeOps::UPDATE,
91            SqliteChangeOp::Delete => SqliteChangeOps::DELETE,
92            SqliteChangeOp::Unknown(_) => SqliteChangeOps::UNKNOWN,
93        }
94    }
95}
96
97/// Describes a single row change event from SQLite.
98///
99/// See: <https://www.sqlite.org/c3ref/update_hook.html>
100#[derive(#[automatically_derived]
impl<'a> ::core::fmt::Debug for SqliteChangeEvent<'a> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field4_finish(f,
            "SqliteChangeEvent", "op", &self.op, "db_name", &self.db_name,
            "table_name", &self.table_name, "rowid", &&self.rowid)
    }
}Debug, #[automatically_derived]
impl<'a> ::core::clone::Clone for SqliteChangeEvent<'a> {
    #[inline]
    fn clone(&self) -> SqliteChangeEvent<'a> {
        let _: ::core::clone::AssertParamIsClone<SqliteChangeOp>;
        let _: ::core::clone::AssertParamIsClone<&'a str>;
        let _: ::core::clone::AssertParamIsClone<&'a str>;
        let _: ::core::clone::AssertParamIsClone<i64>;
        *self
    }
}Clone, #[automatically_derived]
impl<'a> ::core::marker::Copy for SqliteChangeEvent<'a> { }Copy)]
101#[non_exhaustive]
102pub struct SqliteChangeEvent<'a> {
103    /// The operation that triggered this event.
104    pub op: SqliteChangeOp,
105    /// The name of the database the change occurred in: `"main"` for the
106    /// primary database, `"temp"` for temporary tables, or the alias from an
107    /// `ATTACH DATABASE` statement.
108    pub db_name: &'a str,
109    /// The name of the table that was modified.
110    pub table_name: &'a str,
111    /// SQLite's internal 64-bit [rowid](https://www.sqlite.org/rowidtable.html)
112    /// of the affected row. For an `INTEGER PRIMARY KEY` table this equals the
113    /// primary key, otherwise it is a separate hidden value.
114    pub rowid: i64,
115}
116
117impl SqliteChangeEvent<'_> {
118    /// Returns `true` if this change is on the [`table!`](macro@crate::table)
119    /// table `T`, comparing [`table_name`](Self::table_name) against `T`'s
120    /// name. Lets a callback match a typed table marker instead of a string
121    /// literal:
122    ///
123    /// ```rust
124    /// # diesel::table! { users (id) { id -> Integer, name -> Text, } }
125    /// # fn f(change: &diesel::sqlite::SqliteChangeEvent<'_>) {
126    /// if change.is_from(users::table) { /* ... */ }
127    /// # }
128    /// ```
129    ///
130    /// Only the table name is compared, not the database, so a same-named
131    /// table in an `ATTACH`-ed database also matches. Inspect
132    /// [`db_name`](Self::db_name) if you need to tell them apart.
133    pub fn is_from(&self, table: impl NamedTable) -> bool {
134        self.table_name == table.table() && table.schema().is_none_or(|db| self.db_name == db)
135    }
136
137    /// Returns `Some(rowid)` if this change is on table `T`, otherwise `None`.
138    /// Shorthand for [`is_from`](Self::is_from) followed by reading
139    /// [`rowid`](Self::rowid):
140    ///
141    /// ```rust
142    /// # diesel::table! { users (id) { id -> Integer, name -> Text, } }
143    /// # fn f(change: &diesel::sqlite::SqliteChangeEvent<'_>) {
144    /// if let Some(rowid) = change.rowid_in(users::table) { let _ = rowid; }
145    /// # }
146    /// ```
147    pub fn rowid_in(&self, table: impl NamedTable) -> Option<i64> {
148        if self.is_from(table) {
149            Some(self.rowid)
150        } else {
151            None
152        }
153    }
154}
155
156// A helper trait to use `NamedTable` with trait objects
157// without requiring all the super type restrictions
158trait DynNamedTable {
159    fn schema(&self) -> Option<&str>;
160    fn table(&self) -> &str;
161}
162
163impl<T> DynNamedTable for T
164where
165    T: NamedTable,
166{
167    fn schema(&self) -> Option<&str> {
168        NamedTable::schema(self)
169    }
170
171    fn table(&self) -> &str {
172        NamedTable::table(self)
173    }
174}
175
176struct Route {
177    table: Option<Box<dyn DynNamedTable + Send>>,
178    ops: SqliteChangeOps,
179    callback: Box<dyn FnMut(SqliteChangeEvent<'_>) + Send>,
180}
181
182impl Route {
183    fn matches(&self, event: &SqliteChangeEvent<'_>) -> bool {
184        self.ops.matches_op(event.op)
185            && self.table.as_deref().is_none_or(|name| {
186                name.table() == event.table_name
187                    && name.schema().is_none_or(|db| db == event.db_name)
188            })
189    }
190}
191
192/// Routes SQLite row-change events to per-table callbacks, selected by typed
193/// [`table!`](macro@crate::table) markers.
194///
195/// SQLite allows only one update hook per connection. This router is a single
196/// value the caller composes and installs into that one slot with
197/// [`on_update`](super::SqliteConnection::on_update), so the dispatch table is
198/// explicit rather than hidden connection state. Build it with [`on`](Self::on)
199/// and [`on_any`](Self::on_any), then install it:
200///
201/// ```rust
202/// use diesel::prelude::*;
203/// use diesel::sqlite::{SqliteConnection, SqliteChangeOps, SqliteUpdateRouter};
204/// use std::sync::{Arc, Mutex};
205///
206/// diesel::table! { users (id) { id -> Integer, name -> Text, } }
207///
208/// # let conn = &mut SqliteConnection::establish(":memory:").unwrap();
209/// # use diesel::connection::SimpleConnection;
210/// # conn.batch_execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL)").unwrap();
211/// let inserted = Arc::new(Mutex::new(Vec::new()));
212/// let captured = inserted.clone();
213///
214/// conn.on_update(
215///     SqliteUpdateRouter::new()
216///         .on(users::table, SqliteChangeOps::INSERT, move |change| {
217///             captured.lock().unwrap().push(change.rowid);
218///         }),
219/// );
220///
221/// diesel::insert_into(users::table)
222///     .values(users::name.eq("Alice"))
223///     .execute(conn)
224///     .unwrap();
225///
226/// assert_eq!(*inserted.lock().unwrap(), vec![1]);
227/// ```
228///
229/// Every matching route fires for a given event, so overlapping routes (for
230/// example an [`on_any`](Self::on_any) audit log alongside table-specific
231/// handlers) all run. There are no per-route handles: to change the routes,
232/// install a different router or call
233/// [`remove_update_hook`](super::SqliteConnection::remove_update_hook).
234#[allow(missing_debug_implementations)]
235pub struct SqliteUpdateRouter {
236    routes: Vec<Route>,
237}
238
239impl SqliteUpdateRouter {
240    /// Creates an empty router that matches nothing until routes are added.
241    pub fn new() -> Self {
242        SqliteUpdateRouter { routes: Vec::new() }
243    }
244
245    /// Routes changes on `table` matching `ops` to `callback`.
246    ///
247    /// `table` is a table type, either generated by [`table!`](macro@crate::table)
248    /// or a diesel-dynamic-schema table. The schema name is treated as database name
249    /// An unqualified table matches by table name in
250    /// any database, so a same-named table in an `ATTACH`-ed database also
251    /// matches. A schema-qualified `table!` type additionally matches the
252    /// database name, so it fires only for that attached database.
253    pub fn on<T, F>(mut self, table: T, ops: SqliteChangeOps, callback: F) -> Self
254    where
255        T: NamedTable + Send + 'static,
256        F: FnMut(SqliteChangeEvent<'_>) + Send + 'static,
257    {
258        // The table value is taken only for ergonomic call syntax. Its name and
259        // optional schema come from the type's static component.
260        let _ = table;
261        self.routes.push(Route {
262            table: Some(Box::new(table)),
263            ops,
264            callback: Box::new(callback),
265        });
266        self
267    }
268
269    /// Routes changes on any table matching `ops` to `callback`.
270    pub fn on_any<F>(mut self, ops: SqliteChangeOps, callback: F) -> Self
271    where
272        F: FnMut(SqliteChangeEvent<'_>) + Send + 'static,
273    {
274        self.routes.push(Route {
275            table: None,
276            ops,
277            callback: Box::new(callback),
278        });
279        self
280    }
281
282    /// Dispatches an event to every matching route, in build order.
283    fn dispatch(&mut self, event: SqliteChangeEvent<'_>) {
284        for route in &mut self.routes {
285            if route.matches(&event) {
286                (route.callback)(event);
287            }
288        }
289    }
290
291    /// Turns the router into the callback installed by
292    /// [`on_update`](super::SqliteConnection::on_update).
293    pub(crate) fn into_hook(mut self) -> impl FnMut(SqliteChangeEvent<'_>) + Send {
294        move |event| self.dispatch(event)
295    }
296}
297
298impl Default for SqliteUpdateRouter {
299    fn default() -> Self {
300        SqliteUpdateRouter::new()
301    }
302}
303
304#[cfg(test)]
305mod tests {
306    use super::*;
307
308    /// Test-only helper: check mask vs raw FFI op code.
309    impl SqliteChangeOps {
310        fn matches(self, op_code: i32) -> bool {
311            self.matches_op(SqliteChangeOp::from_ffi(op_code))
312        }
313    }
314
315    #[test]
316    fn insert_or_delete_matches_both_but_not_update() {
317        let mask = SqliteChangeOps::INSERT | SqliteChangeOps::DELETE;
318        assert!(mask.matches(ffi::SQLITE_INSERT));
319        assert!(mask.matches(ffi::SQLITE_DELETE));
320        assert!(!mask.matches(ffi::SQLITE_UPDATE));
321    }
322
323    #[test]
324    fn all_matches_all_three() {
325        assert!(SqliteChangeOps::ALL.matches(ffi::SQLITE_INSERT));
326        assert!(SqliteChangeOps::ALL.matches(ffi::SQLITE_UPDATE));
327        assert!(SqliteChangeOps::ALL.matches(ffi::SQLITE_DELETE));
328    }
329
330    #[test]
331    fn combining_identical_masks_is_idempotent() {
332        assert_eq!(
333            SqliteChangeOps::INSERT | SqliteChangeOps::INSERT,
334            SqliteChangeOps::INSERT,
335        );
336    }
337
338    #[test]
339    fn contains_single() {
340        assert!(SqliteChangeOps::INSERT.contains(SqliteChangeOps::INSERT));
341    }
342
343    #[test]
344    fn all_contains_insert_or_delete() {
345        assert!(SqliteChangeOps::ALL.contains(SqliteChangeOps::INSERT | SqliteChangeOps::DELETE));
346    }
347
348    #[test]
349    fn insert_does_not_contain_all() {
350        assert!(!SqliteChangeOps::INSERT.contains(SqliteChangeOps::ALL));
351    }
352
353    #[test]
354    fn from_ffi_insert() {
355        assert_eq!(
356            SqliteChangeOp::from_ffi(ffi::SQLITE_INSERT),
357            SqliteChangeOp::Insert
358        );
359    }
360
361    #[test]
362    fn from_ffi_update() {
363        assert_eq!(
364            SqliteChangeOp::from_ffi(ffi::SQLITE_UPDATE),
365            SqliteChangeOp::Update
366        );
367    }
368
369    #[test]
370    fn from_ffi_delete() {
371        assert_eq!(
372            SqliteChangeOp::from_ffi(ffi::SQLITE_DELETE),
373            SqliteChangeOp::Delete
374        );
375    }
376
377    #[test]
378    fn to_ops_roundtrip() {
379        assert_eq!(SqliteChangeOp::Insert.to_ops(), SqliteChangeOps::INSERT);
380        assert_eq!(SqliteChangeOp::Update.to_ops(), SqliteChangeOps::UPDATE);
381        assert_eq!(SqliteChangeOp::Delete.to_ops(), SqliteChangeOps::DELETE);
382        assert_eq!(
383            SqliteChangeOp::Unknown(999).to_ops(),
384            SqliteChangeOps::UNKNOWN
385        );
386    }
387
388    #[test]
389    fn from_ffi_unknown_code() {
390        assert_eq!(SqliteChangeOp::from_ffi(999), SqliteChangeOp::Unknown(999));
391    }
392
393    #[test]
394    fn sqlite_change_event_is_copy() {
395        let event = SqliteChangeEvent {
396            op: SqliteChangeOp::Delete,
397            db_name: "main",
398            table_name: "posts",
399            rowid: 7,
400        };
401        // Verify Copy by assigning to two bindings without a move error.
402        let a = event;
403        let b = event;
404        assert_eq!(a.rowid, b.rowid);
405    }
406
407    #[test]
408    fn debug_formatting() {
409        // The `bitflags!`-derived Debug names single flags, the exact
410        // composite rendering is bitflags' concern, so only check the names
411        // appear and that empty and composite masks format without panicking.
412        assert!(format!("{:?}", SqliteChangeOps::INSERT).contains("INSERT"));
413        assert!(format!("{:?}", SqliteChangeOps::DELETE).contains("DELETE"));
414        let _ = format!("{:?}", SqliteChangeOps::empty());
415        let _ = format!("{:?}", SqliteChangeOps::ALL);
416    }
417
418    #[test]
419    fn bitand_works() {
420        let mask = SqliteChangeOps::ALL & SqliteChangeOps::INSERT;
421        assert_eq!(mask, SqliteChangeOps::INSERT);
422    }
423
424    // -----------------------------------------------------------------------
425    // Router unit tests (typed `on(table, ...)` routing is covered in hooks.rs,
426    // which has real `table!` markers and a live connection)
427    // -----------------------------------------------------------------------
428
429    fn make_event(
430        op: SqliteChangeOp,
431        table: &'static str,
432        rowid: i64,
433    ) -> SqliteChangeEvent<'static> {
434        SqliteChangeEvent {
435            op,
436            db_name: "main",
437            table_name: table,
438            rowid,
439        }
440    }
441
442    #[test]
443    fn empty_router_dispatches_nothing() {
444        let mut router = SqliteUpdateRouter::new();
445        // Must not panic when there are no routes.
446        router.dispatch(make_event(SqliteChangeOp::Insert, "users", 1));
447    }
448
449    #[test]
450    fn on_any_dispatches_for_every_table() {
451        let fired = std::sync::Arc::new(std::sync::Mutex::new(Vec::new()));
452        let f2 = fired.clone();
453        let mut router = SqliteUpdateRouter::new().on_any(SqliteChangeOps::ALL, move |e| {
454            f2.lock().unwrap().push((e.op, e.rowid));
455        });
456
457        router.dispatch(make_event(SqliteChangeOp::Insert, "users", 1));
458        router.dispatch(make_event(SqliteChangeOp::Delete, "posts", 2));
459
460        assert_eq!(
461            *fired.lock().unwrap(),
462            vec![(SqliteChangeOp::Insert, 1), (SqliteChangeOp::Delete, 2)],
463        );
464    }
465
466    #[test]
467    fn router_filters_by_op_mask() {
468        let fired = std::sync::Arc::new(std::sync::Mutex::new(Vec::new()));
469        let f2 = fired.clone();
470        let mut router = SqliteUpdateRouter::new().on_any(SqliteChangeOps::INSERT, move |e| {
471            f2.lock().unwrap().push(e.rowid);
472        });
473
474        router.dispatch(make_event(SqliteChangeOp::Insert, "users", 1));
475        router.dispatch(make_event(SqliteChangeOp::Update, "users", 2)); // filtered out
476        router.dispatch(make_event(SqliteChangeOp::Delete, "users", 3)); // filtered out
477
478        assert_eq!(*fired.lock().unwrap(), vec![1]);
479    }
480
481    #[test]
482    fn every_matching_route_fires() {
483        let count = std::sync::Arc::new(std::sync::Mutex::new(0u32));
484        let c1 = count.clone();
485        let c2 = count.clone();
486        let mut router = SqliteUpdateRouter::new()
487            .on_any(SqliteChangeOps::ALL, move |_| {
488                *c1.lock().unwrap() += 1;
489            })
490            .on_any(SqliteChangeOps::INSERT, move |_| {
491                *c2.lock().unwrap() += 1;
492            });
493
494        // Insert matches both routes, delete matches only the first.
495        router.dispatch(make_event(SqliteChangeOp::Insert, "users", 1));
496        router.dispatch(make_event(SqliteChangeOp::Delete, "users", 2));
497
498        assert_eq!(*count.lock().unwrap(), 3);
499    }
500}