Skip to content

Commit

Permalink
Next
Browse files Browse the repository at this point in the history
  • Loading branch information
Rigidity committed Oct 31, 2024
1 parent f886bcd commit df67ac6
Show file tree
Hide file tree
Showing 13 changed files with 290 additions and 25 deletions.
2 changes: 2 additions & 0 deletions crates/sage-api/src/records/nft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use specta::Type;
pub struct NftRecord {
pub launcher_id: String,
pub collection_id: Option<String>,
pub collection_name: Option<String>,
pub minter_did: Option<String>,
pub owner_did: Option<String>,
pub visible: bool,
Expand All @@ -19,6 +20,7 @@ pub struct NftRecord {
pub struct NftInfo {
pub launcher_id: String,
pub collection_id: Option<String>,
pub collection_name: Option<String>,
pub minter_did: Option<String>,
pub owner_did: Option<String>,
pub visible: bool,
Expand Down
1 change: 1 addition & 0 deletions crates/sage-api/src/requests/get_nft_collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ use specta::Type;
pub struct GetNftCollections {
pub offset: u32,
pub limit: u32,
pub include_hidden: bool,
}
9 changes: 9 additions & 0 deletions crates/sage-api/src/requests/get_nfts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,13 @@ use specta::Type;
pub struct GetNfts {
pub offset: u32,
pub limit: u32,
pub sort_mode: NftSortMode,
pub include_hidden: bool,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, Type)]
#[serde(rename_all = "snake_case")]
pub enum NftSortMode {
Name,
Recent,
}
217 changes: 216 additions & 1 deletion crates/sage-database/src/primitives/nfts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,20 @@ impl Database {
impl<'a> DatabaseTx<'a> {
pub async fn nft_collections_visible_named(
&mut self,
offset: u32,
limit: u32,
offset: u32,
) -> Result<Vec<NftCollectionRow>> {
nft_collections_visible_named(&mut *self.tx, offset, limit).await
}

pub async fn nft_collections_named(
&mut self,
limit: u32,
offset: u32,
) -> Result<Vec<NftCollectionRow>> {
nft_collections_named(&mut *self.tx, offset, limit).await
}

pub async fn insert_nft_coin(
&mut self,
coin_id: Bytes32,
Expand Down Expand Up @@ -102,6 +110,18 @@ impl<'a> DatabaseTx<'a> {
nfts_visible_named(&mut *self.tx, limit, offset).await
}

pub async fn nfts_visible_recent(&mut self, limit: u32, offset: u32) -> Result<Vec<NftRow>> {
nfts_visible_recent(&mut *self.tx, limit, offset).await
}

pub async fn nfts_named(&mut self, limit: u32, offset: u32) -> Result<Vec<NftRow>> {
nfts_named(&mut *self.tx, limit, offset).await
}

pub async fn nfts_recent(&mut self, limit: u32, offset: u32) -> Result<Vec<NftRow>> {
nfts_recent(&mut *self.tx, limit, offset).await
}

pub async fn nft_count(&mut self) -> Result<u32> {
nft_count(&mut *self.tx).await
}
Expand Down Expand Up @@ -165,6 +185,10 @@ impl<'a> DatabaseTx<'a> {
pub async fn nft_launcher_id(&mut self, coin_id: Bytes32) -> Result<Option<Bytes32>> {
nft_launcher_id(&mut *self.tx, coin_id).await
}

pub async fn nft_collection_name(&mut self, collection_id: Bytes32) -> Result<Option<String>> {
nft_collection_name(&mut *self.tx, collection_id).await
}
}

async fn insert_nft_collection(conn: impl SqliteExecutor<'_>, row: NftCollectionRow) -> Result<()> {
Expand Down Expand Up @@ -198,6 +222,22 @@ async fn insert_nft_collection(conn: impl SqliteExecutor<'_>, row: NftCollection
Ok(())
}

async fn nft_collection_name(
conn: impl SqliteExecutor<'_>,
collection_id: Bytes32,
) -> Result<Option<String>> {
let collection_id = collection_id.as_ref();

let row = sqlx::query!(
"SELECT `name` FROM `nft_collections` WHERE `collection_id` = ?",
collection_id
)
.fetch_one(conn)
.await?;

Ok(row.name)
}

async fn nft_collections_visible_named(
conn: impl SqliteExecutor<'_>,
offset: u32,
Expand Down Expand Up @@ -239,6 +279,46 @@ async fn nft_collections_visible_named(
Ok(collections)
}

async fn nft_collections_named(
conn: impl SqliteExecutor<'_>,
offset: u32,
limit: u32,
) -> Result<Vec<NftCollectionRow>> {
let rows = sqlx::query!(
"
SELECT
`collection_id`,
`did_id`,
`metadata_collection_id`,
`visible`,
`name`,
`icon`
FROM `nft_collections` INDEXED BY `col_named`
ORDER BY `visible` DESC, `is_named` DESC, `name` ASC, `collection_id` ASC
LIMIT ? OFFSET ?
",
limit,
offset
)
.fetch_all(conn)
.await?;

let mut collections = Vec::new();

for row in rows {
collections.push(NftCollectionRow {
collection_id: to_bytes32(&row.collection_id)?,
did_id: to_bytes32(&row.did_id)?,
metadata_collection_id: row.metadata_collection_id,
visible: row.visible,
name: row.name,
icon: row.icon,
});
}

Ok(collections)
}

async fn nft_collection_count(conn: impl SqliteExecutor<'_>) -> Result<u32> {
let row = sqlx::query!(
"
Expand Down Expand Up @@ -631,6 +711,141 @@ async fn nfts_visible_named(
Ok(nfts)
}

async fn nfts_visible_recent(
conn: impl SqliteExecutor<'_>,
limit: u32,
offset: u32,
) -> Result<Vec<NftRow>> {
let rows = sqlx::query!(
"
SELECT
`launcher_id`,
`collection_id`,
`minter_did`,
`owner_did`,
`visible`,
`sensitive_content`,
`name`,
`created_height`,
`metadata_hash`
FROM `nfts` INDEXED BY `nft_recent`
WHERE `visible` = 1
ORDER BY `is_pending` DESC, `created_height` DESC, `launcher_id` ASC
LIMIT ? OFFSET ?
",
limit,
offset
)
.fetch_all(conn)
.await?;

let mut nfts = Vec::new();

for row in rows {
nfts.push(NftRow {
launcher_id: to_bytes32(&row.launcher_id)?,
collection_id: row.collection_id.as_deref().map(to_bytes32).transpose()?,
minter_did: row.minter_did.as_deref().map(to_bytes32).transpose()?,
owner_did: row.owner_did.as_deref().map(to_bytes32).transpose()?,
visible: row.visible,
sensitive_content: row.sensitive_content,
name: row.name,
created_height: row.created_height.map(TryInto::try_into).transpose()?,
metadata_hash: row.metadata_hash.as_deref().map(to_bytes32).transpose()?,
});
}

Ok(nfts)
}

async fn nfts_named(conn: impl SqliteExecutor<'_>, limit: u32, offset: u32) -> Result<Vec<NftRow>> {
let rows = sqlx::query!(
"
SELECT
`launcher_id`,
`collection_id`,
`minter_did`,
`owner_did`,
`visible`,
`sensitive_content`,
`name`,
`created_height`,
`metadata_hash`
FROM `nfts` INDEXED BY `nft_named`
ORDER BY `visible` DESC, `is_named` DESC, `name` ASC, `launcher_id` ASC
LIMIT ? OFFSET ?
",
limit,
offset
)
.fetch_all(conn)
.await?;

let mut nfts = Vec::new();

for row in rows {
nfts.push(NftRow {
launcher_id: to_bytes32(&row.launcher_id)?,
collection_id: row.collection_id.as_deref().map(to_bytes32).transpose()?,
minter_did: row.minter_did.as_deref().map(to_bytes32).transpose()?,
owner_did: row.owner_did.as_deref().map(to_bytes32).transpose()?,
visible: row.visible,
sensitive_content: row.sensitive_content,
name: row.name,
created_height: row.created_height.map(TryInto::try_into).transpose()?,
metadata_hash: row.metadata_hash.as_deref().map(to_bytes32).transpose()?,
});
}

Ok(nfts)
}

async fn nfts_recent(
conn: impl SqliteExecutor<'_>,
limit: u32,
offset: u32,
) -> Result<Vec<NftRow>> {
let rows = sqlx::query!(
"
SELECT
`launcher_id`,
`collection_id`,
`minter_did`,
`owner_did`,
`visible`,
`sensitive_content`,
`name`,
`created_height`,
`metadata_hash`
FROM `nfts` INDEXED BY `nft_recent`
ORDER BY `visible` DESC, `is_pending` DESC, `created_height` DESC, `launcher_id` ASC
LIMIT ? OFFSET ?
",
limit,
offset
)
.fetch_all(conn)
.await?;

let mut nfts = Vec::new();

for row in rows {
nfts.push(NftRow {
launcher_id: to_bytes32(&row.launcher_id)?,
collection_id: row.collection_id.as_deref().map(to_bytes32).transpose()?,
minter_did: row.minter_did.as_deref().map(to_bytes32).transpose()?,
owner_did: row.owner_did.as_deref().map(to_bytes32).transpose()?,
visible: row.visible,
sensitive_content: row.sensitive_content,
name: row.name,
created_height: row.created_height.map(TryInto::try_into).transpose()?,
metadata_hash: row.metadata_hash.as_deref().map(to_bytes32).transpose()?,
});
}

Ok(nfts)
}

async fn insert_nft_coin(
conn: impl SqliteExecutor<'_>,
coin_id: Bytes32,
Expand Down
36 changes: 31 additions & 5 deletions src-tauri/src/commands/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use chia_wallet_sdk::{decode_address, encode_address};
use clvmr::Allocator;
use sage_api::{
Amount, CatRecord, CoinRecord, DidRecord, GetNftCollections, GetNfts, NftCollectionRecord,
NftInfo, NftRecord, NftStatus, PendingTransactionRecord, SyncStatus,
NftInfo, NftRecord, NftSortMode, NftStatus, PendingTransactionRecord, SyncStatus,
};
use sage_database::DidRow;
use sage_wallet::WalletError;
Expand Down Expand Up @@ -304,9 +304,13 @@ pub async fn get_nft_collections(

let mut tx = wallet.db.tx().await?;

let collections = tx
.nft_collections_visible_named(request.limit, request.offset)
.await?;
let collections = if request.include_hidden {
tx.nft_collections_named(request.limit, request.offset)
.await?
} else {
tx.nft_collections_visible_named(request.limit, request.offset)
.await?
};

for col in collections {
records.push(NftCollectionRecord {
Expand Down Expand Up @@ -334,7 +338,15 @@ pub async fn get_nfts(state: State<'_, AppState>, request: GetNfts) -> Result<Ve

let mut tx = wallet.db.tx().await?;

let nfts = tx.nfts_visible_named(request.limit, request.offset).await?;
let nfts = match (request.sort_mode, request.include_hidden) {
(NftSortMode::Name, true) => tx.nfts_named(request.limit, request.offset).await?,
(NftSortMode::Name, false) => tx.nfts_visible_named(request.limit, request.offset).await?,
(NftSortMode::Recent, true) => tx.nfts_recent(request.limit, request.offset).await?,
(NftSortMode::Recent, false) => {
tx.nfts_visible_recent(request.limit, request.offset)
.await?
}
};

for nft in nfts {
let data = if let Some(hash) = tx.data_hash(nft.launcher_id).await? {
Expand All @@ -343,12 +355,19 @@ pub async fn get_nfts(state: State<'_, AppState>, request: GetNfts) -> Result<Ve
None
};

let collection_name = if let Some(collection_id) = nft.collection_id {
tx.nft_collection_name(collection_id).await?
} else {
None
};

records.push(NftRecord {
launcher_id: encode_address(nft.launcher_id.to_bytes(), "nft")?,
collection_id: nft
.collection_id
.map(|col| encode_address(col.to_bytes(), "col"))
.transpose()?,
collection_name,
minter_did: nft
.minter_did
.map(|did| encode_address(did.to_bytes(), "did:chia:"))
Expand Down Expand Up @@ -412,6 +431,12 @@ pub async fn get_nft(state: State<'_, AppState>, launcher_id: String) -> Result<
None
};

let collection_name = if let Some(collection_id) = nft_row.collection_id {
tx.nft_collection_name(collection_id).await?
} else {
None
};

tx.commit().await?;

Ok(Some(NftInfo {
Expand All @@ -420,6 +445,7 @@ pub async fn get_nft(state: State<'_, AppState>, launcher_id: String) -> Result<
.collection_id
.map(|col| encode_address(col.to_bytes(), "col"))
.transpose()?,
collection_name,
minter_did: nft_row
.minter_did
.map(|did| encode_address(did.to_bytes(), "did:chia:"))
Expand Down
Loading

0 comments on commit df67ac6

Please sign in to comment.