object-rainbow-history 0.0.0-a.25

Git-ish diff-by-diff change history
Documentation
use std::collections::BTreeSet;

use futures_util::TryStreamExt;
use macro_rules_attribute::apply;
use object_rainbow::{
    InlineOutput, ListHashes, MaybeHasNiche, Parse, ParseInline, Size, Tagged, ToOutput,
    Topological,
};
use object_rainbow_history::{
    FromIter, Parallel, Return, Sequential,
    remap::{MapToSet, MappedToSet},
};
use object_rainbow_trie::{TrieMap, TrieSet};
use smol_macros::main;
use ulid::Ulid;

#[derive(
    Debug,
    ToOutput,
    InlineOutput,
    Tagged,
    ListHashes,
    Topological,
    Parse,
    ParseInline,
    Clone,
    Copy,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    Size,
    MaybeHasNiche,
)]
struct ChannelId(Ulid);

#[derive(
    Debug,
    ToOutput,
    InlineOutput,
    Tagged,
    ListHashes,
    Topological,
    Parse,
    ParseInline,
    Clone,
    Copy,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    Size,
    MaybeHasNiche,
)]
struct MessageId(Ulid);

#[derive(
    Debug,
    ToOutput,
    InlineOutput,
    Tagged,
    ListHashes,
    Topological,
    Parse,
    ParseInline,
    Clone,
    Copy,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
    Size,
    MaybeHasNiche,
)]
struct UserId(Ulid);

#[derive(
    ToOutput,
    InlineOutput,
    Tagged,
    ListHashes,
    Topological,
    Parse,
    ParseInline,
    Clone,
    Copy,
    PartialEq,
    Eq,
    Size,
    MaybeHasNiche,
)]
struct Message {
    channel: ChannelId,
    user: UserId,
}

#[derive(
    Debug,
    ToOutput,
    InlineOutput,
    Tagged,
    ListHashes,
    Topological,
    Parse,
    ParseInline,
    Clone,
    Copy,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
)]
struct MessageByChannel {
    channel: ChannelId,
    message: MessageId,
    user: UserId,
}

#[derive(
    Debug,
    ToOutput,
    InlineOutput,
    Tagged,
    ListHashes,
    Topological,
    Parse,
    ParseInline,
    Clone,
    Copy,
    PartialEq,
    Eq,
    PartialOrd,
    Ord,
)]
struct MessageByUser {
    user: UserId,
    channel: ChannelId,
    message: MessageId,
}

#[derive(
    ToOutput,
    InlineOutput,
    Tagged,
    ListHashes,
    Topological,
    Parse,
    ParseInline,
    Clone,
    Copy,
    PartialEq,
    Eq,
    Default,
)]
struct MessageToChannel;

#[derive(
    ToOutput,
    InlineOutput,
    Tagged,
    ListHashes,
    Topological,
    Parse,
    ParseInline,
    Clone,
    Copy,
    PartialEq,
    Eq,
    Default,
)]
struct MessageToUser;

impl MapToSet<MessageId, Message> for MessageToChannel {
    type T = MessageByChannel;

    fn map(
        &self,
        message: MessageId,
        Message { channel, user }: Message,
    ) -> impl Send + Future<Output = object_rainbow::Result<Self::T>> {
        async move {
            Ok(MessageByChannel {
                channel,
                message,
                user,
            })
        }
    }
}

impl MapToSet<MessageId, Message> for MessageToUser {
    type T = MessageByUser;

    fn map(
        &self,
        message: MessageId,
        Message { channel, user }: Message,
    ) -> impl Send + Future<Output = object_rainbow::Result<Self::T>> {
        async move {
            Ok(MessageByUser {
                user,
                channel,
                message,
            })
        }
    }
}

type MessagesByChannels =
    Sequential<MappedToSet<MessageToChannel>, FromIter<TrieSet<MessageByChannel>>>;
type MessagesByUsers = Sequential<MappedToSet<MessageToUser>, FromIter<TrieSet<MessageByUser>>>;
type Tree = Sequential<
    Parallel<TrieMap<MessageId, Message>, Return>,
    Parallel<MessagesByChannels, MessagesByUsers>,
>;
type Diff = (Option<Message>, MessageId);
type History = object_rainbow_history::History<Tree, Diff>;

trait Table {
    fn messages_by_channels(
        &self,
    ) -> impl Send + Future<Output = object_rainbow::Result<TrieSet<MessageByChannel>>>;
    fn messages_by_users(
        &self,
    ) -> impl Send + Future<Output = object_rainbow::Result<TrieSet<MessageByUser>>>;
    fn insert(
        &mut self,
        message: MessageId,
        contents: Message,
    ) -> impl Send + Future<Output = object_rainbow::Result<()>>;
    fn delete(
        &mut self,
        message: MessageId,
    ) -> impl Send + Future<Output = object_rainbow::Result<()>>;
}

impl Table for History {
    fn messages_by_channels(
        &self,
    ) -> impl Send + Future<Output = object_rainbow::Result<TrieSet<MessageByChannel>>> {
        async move { Ok(self.tree().await?.second().a().second().0.clone()) }
    }

    fn messages_by_users(
        &self,
    ) -> impl Send + Future<Output = object_rainbow::Result<TrieSet<MessageByUser>>> {
        async move { Ok(self.tree().await?.second().b().second().0.clone()) }
    }

    fn insert(
        &mut self,
        message: MessageId,
        contents: Message,
    ) -> impl Send + Future<Output = object_rainbow::Result<()>> {
        self.commit((Some(contents), message))
    }

    fn delete(
        &mut self,
        message: MessageId,
    ) -> impl Send + Future<Output = object_rainbow::Result<()>> {
        self.commit((None, message))
    }
}

#[apply(main!)]
async fn main() -> object_rainbow::Result<()> {
    let mut history = History::new();
    let channel = ChannelId(Ulid::new());
    let user = UserId(Ulid::new());
    let message = MessageId(Ulid::new());
    history.insert(message, Message { channel, user }).await?;
    assert!(
        history
            .messages_by_channels()
            .await?
            .contains(&MessageByChannel {
                channel,
                message,
                user,
            })
            .await?,
    );
    assert!(
        history
            .messages_by_users()
            .await?
            .contains(&MessageByUser {
                user,
                channel,
                message,
            })
            .await?,
    );
    let messages_by_channel = history
        .messages_by_channels()
        .await?
        .range_stream(
            &MessageByChannel {
                channel,
                message: MessageId(Ulid::from_parts(u64::MIN, u128::MIN)),
                user: UserId(Ulid::from_parts(u64::MIN, u128::MIN)),
            }..=&MessageByChannel {
                channel,
                message: MessageId(Ulid::from_parts(u64::MAX, u128::MAX)),
                user: UserId(Ulid::from_parts(u64::MAX, u128::MAX)),
            },
        )
        .try_collect::<BTreeSet<_>>()
        .await?;
    assert_eq!(
        messages_by_channel,
        BTreeSet::from([MessageByChannel {
            channel,
            message,
            user,
        }]),
    );
    history.delete(message).await?;
    assert!(
        !history
            .messages_by_channels()
            .await?
            .contains(&MessageByChannel {
                channel,
                message,
                user,
            })
            .await?,
    );
    assert!(
        !history
            .messages_by_users()
            .await?
            .contains(&MessageByUser {
                user,
                channel,
                message,
            })
            .await?,
    );
    Ok(())
}