Skip to content

Commit

Permalink
Merge pull request #356 from holaplex/dev
Browse files Browse the repository at this point in the history
Release - Wallet connection from/to counts, NFT counts, No Dup Attributes
  • Loading branch information
kespinola authored Apr 11, 2022
2 parents 2fe5b05 + 5498e1b commit 8778f1c
Show file tree
Hide file tree
Showing 28 changed files with 569 additions and 65 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/dispatch_to_docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Send event to rebuild docs

on:
push:
branches: [dev, master]

jobs:
dispatch:
runs-on: ubuntu-latest
steps:
- name: Dispatch event to docs repo
uses: peter-evans/repository-dispatch@v2
with:
token: ${{ secrets.DOCS_REPO_ACCESS_TOKEN }}
repository: holaplex/marketplace-api-docs
event-type: api_update
client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}'
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
drop table attributes;

alter table temp_attributes rename to attributes;

drop function create_temp_attributes_table();
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
create function create_temp_attributes_table()
returns void
language plpgsql as
$func$
begin
if not exists (select from pg_catalog.pg_tables
where schemaname = 'public'
and tablename = 'temp_attributes') then

alter table attributes rename to temp_attributes;

create table attributes (
metadata_address varchar(48) not null,
value text,
trait_type text,
id uuid primary key default gen_random_uuid(),
first_verified_creator varchar(48) null,
unique (metadata_address, value, trait_type)
);

create index if not exists attr_metadata_address_index on
attributes using hash (metadata_address);

create index if not exists attr_first_verified_creator_index
on attributes (first_verified_creator);

create index if not exists attr_trait_type_value_index
on attributes (trait_type, value);

end if;
end
$func$;

select create_temp_attributes_table();
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
drop index if exists buyer_bid_receipts_idx;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
create index if not exists buyer_bid_receipts_idx on
bid_receipts using hash (buyer);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
drop index if exists seller_listing_receipts_idx;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
create index if not exists seller_listing_receipts_idx on
listing_receipts using hash (seller);
2 changes: 1 addition & 1 deletion crates/core/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use std::env;

pub use diesel::{
backend::Backend,
debug_query, delete, insert_into,
debug_query, delete, expression, insert_into,
pg::{upsert::excluded, Pg},
query_dsl,
result::Error,
Expand Down
1 change: 1 addition & 0 deletions crates/core/src/db/queries/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod graph_connection;
pub mod listing_denylist;
pub mod metadata_edition;
pub mod metadatas;
pub mod nft_count;
pub mod stats;
pub mod store_denylist;
pub mod twitter_handle_name_service;
219 changes: 219 additions & 0 deletions crates/core/src/db/queries/nft_count.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
//! Query utilities for looking up nft counts

use diesel::{
expression::{operators::Eq, AsExpression, NonAggregate},
pg::Pg,
prelude::*,
query_builder::QueryFragment,
query_source::joins::{Inner, Join, JoinOn},
serialize::ToSql,
sql_types::Text,
AppearsOnTable,
};

use crate::{
db::{
any,
tables::{bid_receipts, listing_receipts, metadata_creators, metadatas, token_accounts},
Connection,
},
error::prelude::*,
};

/// Handles queries for total nfts count
///
/// # Errors
/// returns an error when the underlying queries throw an error
pub fn total<C: ToSql<Text, Pg>>(conn: &Connection, creators: &[C]) -> Result<i64> {
metadatas::table
.inner_join(
metadata_creators::table.on(metadatas::address.eq(metadata_creators::metadata_address)),
)
.filter(metadata_creators::creator_address.eq(any(creators)))
.filter(metadata_creators::verified.eq(true))
.count()
.get_result(conn)
.context("failed to load total nfts count")
}

/// Handles queries for listed nfts count
///
/// # Errors
/// returns an error when the underlying queries throw an error
pub fn listed<C: ToSql<Text, Pg>, L: ToSql<Text, Pg>>(
conn: &Connection,
creators: &[C],
listed: Option<&[L]>,
) -> Result<i64> {
let mut query = metadatas::table
.inner_join(
metadata_creators::table.on(metadatas::address.eq(metadata_creators::metadata_address)),
)
.inner_join(listing_receipts::table.on(metadatas::address.eq(listing_receipts::metadata)))
.into_boxed();

if let Some(listed) = listed {
query = query.filter(listing_receipts::auction_house.eq(any(listed)));
}

query
.filter(metadata_creators::creator_address.eq(any(creators)))
.filter(metadata_creators::verified.eq(true))
.filter(listing_receipts::purchase_receipt.is_null())
.filter(listing_receipts::canceled_at.is_null())
.count()
.get_result(conn)
.context("failed to load listed nfts count")
}

/// Handles queries for owned nfts count
///
/// # Errors
/// returns an error when the underlying queries throw an error
pub fn owned<W: AsExpression<Text>, C: ToSql<Text, Pg>>(
conn: &Connection,
wallet: W,
creators: Option<&[C]>,
) -> Result<i64>
where
W::Expression: NonAggregate
+ QueryFragment<Pg>
+ AppearsOnTable<
JoinOn<
Join<
JoinOn<
Join<metadatas::table, metadata_creators::table, Inner>,
Eq<metadatas::address, metadata_creators::metadata_address>,
>,
token_accounts::table,
Inner,
>,
Eq<metadatas::mint_address, token_accounts::mint_address>,
>,
>,
{
let mut query = metadatas::table
.inner_join(
metadata_creators::table.on(metadatas::address.eq(metadata_creators::metadata_address)),
)
.inner_join(
token_accounts::table.on(metadatas::mint_address.eq(token_accounts::mint_address)),
)
.into_boxed();

if let Some(creators) = creators {
query = query.filter(metadata_creators::creator_address.eq(any(creators)));
}

query
.filter(metadata_creators::verified.eq(true))
.filter(token_accounts::amount.eq(1))
.filter(token_accounts::owner_address.eq(wallet))
.count()
.get_result(conn)
.context("failed to load owned nfts count")
}

/// Handles queries for nfts count for a wallet with optional creators and auction house filters
///
/// # Errors
/// returns an error when the underlying queries throw an error
pub fn offered<W: AsExpression<Text>, C: ToSql<Text, Pg>, H: ToSql<Text, Pg>>(
conn: &Connection,
wallet: W,
creators: Option<&[C]>,
auction_houses: Option<&[H]>,
) -> Result<i64>
where
W::Expression: NonAggregate
+ QueryFragment<Pg>
+ AppearsOnTable<
JoinOn<
Join<
JoinOn<
Join<metadatas::table, metadata_creators::table, Inner>,
Eq<metadatas::address, metadata_creators::metadata_address>,
>,
bid_receipts::table,
Inner,
>,
Eq<metadatas::address, bid_receipts::metadata>,
>,
>,
{
let mut query = metadatas::table
.inner_join(
metadata_creators::table.on(metadatas::address.eq(metadata_creators::metadata_address)),
)
.inner_join(bid_receipts::table.on(metadatas::address.eq(bid_receipts::metadata)))
.into_boxed();

if let Some(auction_houses) = auction_houses {
query = query.filter(bid_receipts::auction_house.eq(any(auction_houses)));
}

if let Some(creators) = creators {
query = query.filter(metadata_creators::creator_address.eq(any(creators)));
}

query
.filter(metadata_creators::verified.eq(true))
.filter(bid_receipts::buyer.eq(wallet))
.filter(bid_receipts::purchase_receipt.is_null())
.filter(bid_receipts::canceled_at.is_null())
.count()
.get_result(conn)
.context("failed to load nfts count of open offers for a wallet")
}

/// Handles queries for wallet listed nfts count
///
/// # Errors
/// returns an error when the underlying queries throw an error
pub fn wallet_listed<W: AsExpression<Text>, C: ToSql<Text, Pg>, L: ToSql<Text, Pg>>(
conn: &Connection,
wallet: W,
creators: Option<&[C]>,
listed: Option<&[L]>,
) -> Result<i64>
where
W::Expression: NonAggregate
+ QueryFragment<Pg>
+ AppearsOnTable<
JoinOn<
Join<
JoinOn<
Join<metadatas::table, metadata_creators::table, Inner>,
Eq<metadatas::address, metadata_creators::metadata_address>,
>,
listing_receipts::table,
Inner,
>,
Eq<metadatas::address, listing_receipts::metadata>,
>,
>,
{
let mut query = metadatas::table
.inner_join(
metadata_creators::table.on(metadatas::address.eq(metadata_creators::metadata_address)),
)
.inner_join(listing_receipts::table.on(metadatas::address.eq(listing_receipts::metadata)))
.into_boxed();

if let Some(listed) = listed {
query = query.filter(listing_receipts::auction_house.eq(any(listed)));
}

if let Some(creators) = creators {
query = query.filter(metadata_creators::creator_address.eq(any(creators)));
}

query
.filter(metadata_creators::verified.eq(true))
.filter(listing_receipts::purchase_receipt.is_null())
.filter(listing_receipts::canceled_at.is_null())
.filter(listing_receipts::seller.eq(wallet))
.count()
.get_result(conn)
.context("failed to load listed nfts count")
}
18 changes: 15 additions & 3 deletions crates/core/src/db/queries/twitter_handle_name_service.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
//! Query utilities for `graph_connections` table.

use diesel::OptionalExtension;
use diesel::{
expression::{AsExpression, NonAggregate},
pg::Pg,
query_builder::{QueryFragment, QueryId},
sql_types::Text,
AppearsOnTable, OptionalExtension,
};

use crate::{
db::{tables::twitter_handle_name_services, Connection},
Expand All @@ -12,11 +18,17 @@ use crate::{
///
/// # Errors
/// This function fails if the underlying query fails to execute.
pub fn get(conn: &Connection, address: String) -> Result<Option<String>> {
pub fn get<A: AsExpression<Text>>(conn: &Connection, address: A) -> Result<Option<String>>
where
A::Expression: NonAggregate
+ QueryId
+ QueryFragment<Pg>
+ AppearsOnTable<twitter_handle_name_services::table>,
{
twitter_handle_name_services::table
.filter(twitter_handle_name_services::wallet_address.eq(address))
.select(twitter_handle_name_services::twitter_handle)
.first::<String>(conn)
.first(conn)
.optional()
.context("Failed to load twitter handle")
}
15 changes: 15 additions & 0 deletions crates/core/src/db/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,20 @@ table! {
}
}

table! {
use diesel::sql_types::*;
use diesel_full_text_search::{TsVector as Tsvector, TsQuery as Tsquery};
use crate::db::custom_types::{SettingType as Settingtype, Mode, TokenStandard as Token_standard};

temp_attributes (id) {
metadata_address -> Varchar,
value -> Nullable<Text>,
trait_type -> Nullable<Text>,
id -> Uuid,
first_verified_creator -> Nullable<Varchar>,
}
}

table! {
use diesel::sql_types::*;
use diesel_full_text_search::{TsVector as Tsvector, TsQuery as Tsquery};
Expand Down Expand Up @@ -916,6 +930,7 @@ allow_tables_to_appear_in_same_query!(
storefronts,
stores,
sub_account_infos,
temp_attributes,
token_accounts,
transactions,
twitter_handle_name_services,
Expand Down
3 changes: 2 additions & 1 deletion crates/graphql/src/schema/dataloaders/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ pub(self) mod prelude {
pub(super) use super::{
super::prelude::*,
batcher::{
BatchIter, BatchMap, BatchResult, Batcher, TryBatchFn, TryBatchMap, TwitterBatcher,
BatchIter, BatchMap, BatchResult, Batcher, Error, TryBatchFn, TryBatchMap,
TwitterBatcher,
},
};
}
Expand Down
2 changes: 1 addition & 1 deletion crates/graphql/src/schema/dataloaders/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use futures_util::future::join_all;
use itertools::Either;
use objects::profile::{TwitterProfile, TwitterUserProfileResponse};

use super::{batcher::Error, prelude::*};
use super::prelude::*;

const TWITTER_SCREEN_NAME_CHUNKS: usize = 100;

Expand Down
Loading

0 comments on commit 8778f1c

Please sign in to comment.