//! The [`Table`] and [`TableWithPrimaryKey`] traits,
//! which allow certain simple queries of the client cache,
//! and expose row callbacks which run when subscribed rows are inserted, deleted or updated.
//!
//! These traits are implemented by "table handles,"
//! types generated by the SpacetimeDB CLI's module-specific codegen
//! which mediate access to tables in the client cache.
//! Obtain a table handle by calling a method on `ctx.db`, where `ctx` is a `DbConnection` or `EventContext`.

/// Trait implemented by table handles, which mediate access to tables in the client cache.
///
/// Obtain a table handle by calling a method on `ctx.db`, where `ctx` is a `DbConnection` or `EventContext`.
pub trait Table {
    /// The type of rows stored in this table.
    type Row: 'static;

    /// The `EventContext` type generated for the module which defines this table.
    type EventContext;

    /// The number of subscribed rows in the client cache.
    fn count(&self) -> u64;

    /// An iterator over all the subscribed rows in the client cache.
    fn iter(&self) -> impl Iterator<Item = Self::Row> + '_;

    type InsertCallbackId;
    /// Register a callback to run whenever a subscribed row is inserted into the client cache.
    ///
    /// The returned [`Self::InsertCallbackId`] can be passed to [`Self::remove_on_insert`]
    /// to cancel the callback.
    fn on_insert(
        &self,
        callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
    ) -> Self::InsertCallbackId;
    /// Cancel a callback previously registered by [`Self::on_insert`], causing it not to run in the future.
    fn remove_on_insert(&self, callback: Self::InsertCallbackId);

    type DeleteCallbackId;
    /// Register a callback to run whenever a subscribed row is deleted from the client cache.
    ///
    /// The returned [`Self::DeleteCallbackId`] can be passed to [`Self::remove_on_delete`]
    /// to cancel the callback.
    fn on_delete(
        &self,
        callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
    ) -> Self::DeleteCallbackId;
    /// Cancel a callback previously registered by [`Self::on_delete`], causing it not to run in the future.
    fn remove_on_delete(&self, callback: Self::DeleteCallbackId);
}

/// Subtrait of [`Table`] implemented only by tables with a column designated as a primary key,
/// which allows the SDK to identify updates.
///
/// SpacetimeDB does not have a special notion of updates as a primitive operation.
/// Instead, an update is a delete followed by an insert
/// of rows with the same primary key within the same transaction.
/// This means that the module's calls to `ctx.db.some_table().unique_column().update(...)`
/// may not result in an update event on the client if `unique_column` is not the primary key,
/// and that clients may observe update events resulting from deletes and inserts by the module
/// without going through such an `update` method.
pub trait TableWithPrimaryKey: Table {
    type UpdateCallbackId;
    /// Register a callback to run whenever a subscribed row is updated within a transaction,
    /// with an old version deleted and a new version inserted with the same primary key.
    ///
    /// The callback's arguments are `(ctx, old, new)`,
    /// where `old` is the deleted row, and `new` is the inserted row.
    ///
    /// The returned [`Self::UpdateCallbackId`] can be passed to [`Self::remove_on_update`]
    /// to cancel the callback.
    fn on_update(
        &self,
        callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
    ) -> Self::UpdateCallbackId;
    /// Cancel a callback previously registered by [`Self::on_update`], causing it not to run in the future.
    fn remove_on_update(&self, callback: Self::UpdateCallbackId);
}
