cido 0.2.0

Core traits and implementations for indexing with cido
Documentation
use crate::prelude::*;
#[_impls]
use chrono::{DateTime, Utc};
use cido_macros::_impls;

/// Table descriptors can be automatically generated at compile time from
/// the information provided through the proc macros or instantiated as consts.
#[derive(Clone)]
pub struct TableDescriptor<T: Transformer> {
  pub base_table_name: &'static str,
  /// Includes all the fields in the table, including any meta fields used internally,
  /// like block number/range, etc.
  pub fields: &'static [ColDescription],
  pub id_field: &'static ColDescription,
  pub event_order_field: &'static ColDescription,
  pub constraints: &'static [TableConstraint],
  pub record_kind: RecordType,
  pub max_table_rows: u64,
  pub max_table_bytes: u64,
  pub table_resolver: fn() -> &'static std::sync::OnceLock<TableResolver<T>>,
}

impl<T: Transformer> TableDescriptor<T> {
  pub fn table_resolver(&self) -> &'static TableResolver<T> {
    (self.table_resolver)().get().unwrap_or_else(|| {
      panic!(
        "TableResolver for {} has already been initialized",
        std::any::type_name::<T>()
      )
    })
  }
  pub(crate) fn fields_list(&self) -> impl Iterator<Item = &'static str> {
    self.fields.iter().map(|c| c.name)
  }

  /// Returns the column name which holds the information about which
  /// event order (usually block number)
  pub(crate) const fn event_order_field(&self) -> &'static str {
    &self.event_order_field.name
  }
}

#[derive(Clone)]
pub struct ColDescription {
  pub name: &'static str,
  pub type_fn: fn() -> sqlx::postgres::PgTypeInfo,
  pub constraints: &'static [ColConstraint],
  pub is_static: bool,
  pub indexed: bool,
}

pub struct TableConstraint {
  pub(crate) name: Option<&'static str>,
  pub(crate) apply_only_current: bool,
  pub(crate) apply_not_current: bool,
  pub(crate) constraint_type: TableConstraintType,
}

impl TableConstraint {
  pub const fn new(constraint_type: TableConstraintType, name: Option<&'static str>) -> Self {
    Self {
      name,
      apply_only_current: false,
      apply_not_current: false,
      constraint_type,
    }
  }

  pub const fn apply_to_current(mut self) -> Self {
    assert!(!self.apply_not_current);
    self.apply_only_current = true;
    self
  }

  pub const fn apply_to_non_current(mut self) -> Self {
    assert!(!self.apply_only_current);
    self.apply_not_current = true;
    self
  }
}

#[non_exhaustive]
pub enum TableConstraintType {
  Exclude { method: &'static str },
  Unique { columns: &'static [&'static str] },
  PrimaryKey { columns: &'static [&'static str] },
  Check { check: &'static str },
  Raw { raw_sql: &'static str },
}

#[derive(Clone, Copy)]
pub enum ColConstraint {
  PrimaryKey,
  NotNull,
  Check { check: &'static str },
}

pub trait LoadLocator: core::fmt::Display {}

#[_impls]
impl LoadLocator for &str {}

#[_impls]
pub struct TableResolver<T: Transformer> {
  inner: std::marker::PhantomData<fn() -> T>,
}

#[_impls]
impl<T: Transformer> TableResolver<T> {
  pub fn get_table_for_block_number(
    &self,
    number: <<T::Cidomap as Cidomap>::Network as Network>::BlockNumber,
  ) -> impl LoadLocator {
    "unknown"
  }
  pub fn get_tables_for_range(
    &self,
    range: &<<T::Cidomap as Cidomap>::Network as Network>::BlockNumberRange,
  ) -> impl LoadLocator {
    "unknown"
  }
}

#[_impls]
pub struct MetaInfo<N: Network> {
  sync_block: N::BlockNumber,
  chain_head: N::BlockNumber,
  last_synced: DateTime<Utc>,
  initialized_at: DateTime<Utc>,
}

#[_impls]
impl<N: Network> MetaInfo<N> {
  pub async fn get<'a, 'c: 'a, C>(conn: C) -> sqlx::Result<Self>
  where
    C: sqlx::Executor<'c, Database = sqlx::Postgres> + 'a + Send,
  {
    unimplemented!()
  }
  pub fn get_sync_block(&self) -> N::BlockNumber {
    self.sync_block
  }
}

#[_impls]
#[async_graphql::Object]
impl<N: Network> MetaInfo<N> {
  #[graphql(name = "lastSynced")]
  pub async fn graphql_last_synced(&self) -> DateTime<Utc> {
    self.last_synced
  }

  #[graphql(name = "syncBlock")]
  pub async fn graphql_sync_block(&self) -> N::BlockNumber {
    self.get_sync_block()
  }

  #[graphql(name = "initializedAt")]
  pub async fn graphql_initialized_at(&self) -> DateTime<Utc> {
    self.initialized_at
  }

  #[graphql(name = "synced")]
  pub async fn graphql_synced(
    &self,
    ctx: &async_graphql::Context<'_>,
  ) -> async_graphql::Result<bool> {
    let _ = ctx;
    Ok(self.chain_head <= self.sync_block)
  }

  #[graphql(name = "chainHead")]
  pub async fn graphql_chain_head(&self) -> N::BlockNumber {
    self.chain_head
  }
}