Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8/7 Release #173

Merged
merged 7 commits into from
Aug 7, 2023
30 changes: 30 additions & 0 deletions api/src/dataloaders/collection_mints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,33 @@ impl DataLoader<String> for OwnerLoader {
}))
}
}

#[derive(Debug, Clone)]
pub struct CollectionMintLoader {
pub db: Connection,
}

impl CollectionMintLoader {
#[must_use]
pub fn new(db: Connection) -> Self {
Self { db }
}
}

#[async_trait]
impl DataLoader<Uuid> for CollectionMintLoader {
type Error = FieldError;
type Value = collection_mints::CollectionMint;

async fn load(&self, keys: &[Uuid]) -> Result<HashMap<Uuid, Self::Value>, Self::Error> {
let collection_mints = collection_mints::Entity::find()
.filter(collection_mints::Column::Id.is_in(keys.iter().map(ToOwned::to_owned)))
.all(self.db.get())
.await?;

Ok(collection_mints
.into_iter()
.map(|collection_mint| (collection_mint.id, collection_mint.into()))
.collect())
}
}
37 changes: 37 additions & 0 deletions api/src/dataloaders/mint_histories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,40 @@ impl DataLoader<Uuid> for DropMintHistoryLoader {
.collect())
}
}

#[derive(Debug, Clone)]
pub struct MinterLoader {
pub db: Connection,
}

impl MinterLoader {
#[must_use]
pub fn new(db: Connection) -> Self {
Self { db }
}
}

#[async_trait]
impl DataLoader<String> for MinterLoader {
type Error = FieldError;
type Value = Vec<mint_histories::Model>;

async fn load(&self, keys: &[String]) -> Result<HashMap<String, Self::Value>, Self::Error> {
let mint_histories = mint_histories::Entity::find()
.filter(mint_histories::Column::Wallet.is_in(keys.iter().map(ToOwned::to_owned)))
.all(self.db.get())
.await?;

Ok(mint_histories
.into_iter()
.fold(HashMap::new(), |mut acc, mint_history| {
acc.entry(mint_history.wallet.clone())
.or_insert_with(Vec::new);

acc.entry(mint_history.wallet.clone())
.and_modify(|mint_histories| mint_histories.push(mint_history));

acc
}))
}
}
7 changes: 5 additions & 2 deletions api/src/dataloaders/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ mod project_collections;
pub use collection::Loader as CollectionLoader;
pub use collection_drop::Loader as CollectionDropLoader;
pub use collection_mints::{
Loader as CollectionMintsLoader, OwnerLoader as CollectionMintsOwnerLoader,
CollectionMintLoader, Loader as CollectionMintsLoader,
OwnerLoader as CollectionMintsOwnerLoader,
};
pub use creators::Loader as CreatorsLoader;
pub use drop::Loader as DropLoader;
Expand All @@ -22,6 +23,8 @@ pub use holders::Loader as HoldersLoader;
pub use metadata_json::{
AttributesLoader as MetadataJsonAttributesLoader, Loader as MetadataJsonLoader,
};
pub use mint_histories::{CollectionMintHistoryLoader, DropMintHistoryLoader};
pub use mint_histories::{
CollectionMintHistoryLoader, DropMintHistoryLoader, MinterLoader as MinterMintHistoryLoader,
};
pub use project_collection::ProjectCollectionLoader;
pub use project_collections::ProjectCollectionsLoader;
20 changes: 17 additions & 3 deletions api/src/entities/mint_histories.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.11.3

use async_graphql::SimpleObject;
use async_graphql::{ComplexObject, Context, Result, SimpleObject};
use sea_orm::entity::prelude::*;

use super::sea_orm_active_enums::CreationStatus;
use super::{collection_mints::CollectionMint, sea_orm_active_enums::CreationStatus};
use crate::AppContext;

/// A record of a minted NFT.
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, SimpleObject)]
#[sea_orm(table_name = "mint_histories")]
#[graphql(concrete(name = "MintHistory", params()))]
#[graphql(concrete(name = "MintHistory", params()), complex)]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id: Uuid,
Expand All @@ -28,6 +29,19 @@ pub struct Model {
pub collection_id: Uuid,
}

#[ComplexObject]
impl Model {
/// The minted NFT.
async fn mint(&self, ctx: &Context<'_>) -> Result<Option<CollectionMint>> {
let AppContext {
single_collection_mint_loader,
..
} = ctx.data::<AppContext>()?;

single_collection_mint_loader.load_one(self.mint_id).await
}
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
#[sea_orm(
Expand Down
16 changes: 12 additions & 4 deletions api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
};
use blockchains::{polygon::Polygon, solana::Solana};
use dataloaders::{
CollectionDropLoader, CollectionLoader, CollectionMintHistoryLoader, CollectionMintsLoader,
CollectionMintsOwnerLoader, CreatorsLoader, DropLoader, DropMintHistoryLoader, HoldersLoader,
MetadataJsonAttributesLoader, MetadataJsonLoader, ProjectCollectionLoader,
ProjectCollectionsLoader, ProjectDropsLoader,
CollectionDropLoader, CollectionLoader, CollectionMintHistoryLoader, CollectionMintLoader,
CollectionMintsLoader, CollectionMintsOwnerLoader, CreatorsLoader, DropLoader,
DropMintHistoryLoader, HoldersLoader, MetadataJsonAttributesLoader, MetadataJsonLoader,
MinterMintHistoryLoader, ProjectCollectionLoader, ProjectCollectionsLoader, ProjectDropsLoader,
};
use db::Connection;
use hub_core::{
Expand Down Expand Up @@ -235,7 +235,7 @@

impl AppState {
#[must_use]
pub fn new(

Check warning on line 238 in api/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy/check/doc

this function has too many arguments (8/7)

Check warning on line 238 in api/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy/check/doc

this function has too many arguments (8/7)
schema: AppSchema,
connection: Connection,
producer: Producer<NftEvents>,
Expand Down Expand Up @@ -270,13 +270,15 @@
metadata_json_loader: DataLoader<MetadataJsonLoader>,
metadata_json_attributes_loader: DataLoader<MetadataJsonAttributesLoader>,
collection_mints_loader: DataLoader<CollectionMintsLoader>,
single_collection_mint_loader: DataLoader<CollectionMintLoader>,
collection_mints_owner_loader: DataLoader<CollectionMintsOwnerLoader>,
collection_drop_loader: DataLoader<CollectionDropLoader>,
drop_loader: DataLoader<DropLoader>,
creators_loader: DataLoader<CreatorsLoader>,
holders_loader: DataLoader<HoldersLoader>,
collection_mint_history_loader: DataLoader<CollectionMintHistoryLoader>,
drop_mint_history_loader: DataLoader<DropMintHistoryLoader>,
minter_mint_history_loader: DataLoader<MinterMintHistoryLoader>,
}

impl AppContext {
Expand All @@ -292,7 +294,7 @@
let collection_loader = DataLoader::new(CollectionLoader::new(db.clone()), tokio::spawn);
let project_collections_loader =
DataLoader::new(ProjectCollectionsLoader::new(db.clone()), tokio::spawn);
let project_collection_loader =

Check warning on line 297 in api/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy/check/doc

binding's name is too similar to existing binding

Check warning on line 297 in api/src/lib.rs

View workflow job for this annotation

GitHub Actions / clippy/check/doc

binding's name is too similar to existing binding
DataLoader::new(ProjectCollectionLoader::new(db.clone()), tokio::spawn);
let metadata_json_loader =
DataLoader::new(MetadataJsonLoader::new(db.clone()), tokio::spawn);
Expand All @@ -311,6 +313,10 @@
DataLoader::new(CollectionMintHistoryLoader::new(db.clone()), tokio::spawn);
let drop_mint_history_loader =
DataLoader::new(DropMintHistoryLoader::new(db.clone()), tokio::spawn);
let single_collection_mint_loader =
DataLoader::new(CollectionMintLoader::new(db.clone()), tokio::spawn);
let minter_mint_history_loader =
DataLoader::new(MinterMintHistoryLoader::new(db.clone()), tokio::spawn);

Self {
db,
Expand All @@ -324,13 +330,15 @@
metadata_json_loader,
metadata_json_attributes_loader,
collection_mints_loader,
single_collection_mint_loader,
collection_mints_owner_loader,
collection_drop_loader,
drop_loader,
creators_loader,
holders_loader,
collection_mint_history_loader,
drop_mint_history_loader,
minter_mint_history_loader,
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion api/src/objects/collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
};

/// An NFT collection that has either a fixed supply or unlimited mints. NFT collections are deployed to a desired blockchain.
/// On Solana, when the collection is associated to a drop it is a master_edition. When the collection is not associated to a drop it is a sized Metaplex certified collection.
/// On Solana, when the collection is associated to a drop it is a `master_edition`. When the collection is not associated to a drop it is a sized Metaplex certified collection.
/// On EVM chains, the collection is a ERC-1155 token.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Collection {
Expand Down
30 changes: 29 additions & 1 deletion api/src/objects/customer.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use async_graphql::{ComplexObject, Context, Result, SimpleObject};
use hub_core::uuid::Uuid;

use crate::{entities::collection_mints, AppContext};
use crate::{
entities::{collection_mints, mint_histories},
AppContext,
};

/// A project customer.
#[derive(SimpleObject, Debug, Clone)]
Expand Down Expand Up @@ -40,4 +43,29 @@ impl Customer {
Ok(None)
}
}

/// The NFTs minted by the customer.
#[graphql(requires = "addresses")]
async fn mint_histories(
&self,
ctx: &Context<'_>,
) -> Result<Option<Vec<mint_histories::Model>>> {
let AppContext {
minter_mint_history_loader,
..
} = ctx.data::<AppContext>()?;

if let Some(addresses) = self.addresses.clone() {
Ok(Some(
minter_mint_history_loader
.load_many(addresses)
.await?
.into_values()
.flatten()
.collect(),
))
} else {
Ok(None)
}
}
}
Loading