diff --git a/das_api/src/api/api_impl.rs b/das_api/src/api/api_impl.rs index 84ca2c550..a4ca22241 100644 --- a/das_api/src/api/api_impl.rs +++ b/das_api/src/api/api_impl.rs @@ -12,7 +12,7 @@ use digital_asset_types::{ get_proof_for_asset, get_token_accounts, search_assets, }, rpc::{ - filter::{AssetSortBy, SearchConditionType}, + filter::SearchConditionType, response::{GetGroupingResponse, TokenAccountList}, OwnershipModel, RoyaltyModel, }, @@ -102,11 +102,6 @@ impl DasApi { if cursor.is_some() { return Err(DasApiError::PaginationError); } - if let Some(sort) = &sorting { - if sort.sort_by != AssetSortBy::Id { - return Err(DasApiError::PaginationSortingValidationError); - } - } validate_pubkey(before.clone())?; is_cursor_enabled = false; } @@ -115,21 +110,14 @@ impl DasApi { if cursor.is_some() { return Err(DasApiError::PaginationError); } - if let Some(sort) = &sorting { - if sort.sort_by != AssetSortBy::Id { - return Err(DasApiError::PaginationSortingValidationError); - } - } + validate_pubkey(after.clone())?; is_cursor_enabled = false; } page_opt.limit = limit.map(|x| x as u64).unwrap_or(1000); if is_cursor_enabled { - if let Some(sort) = &sorting { - if sort.sort_by != AssetSortBy::Id { - return Err(DasApiError::PaginationSortingValidationError); - } + if sorting.is_some() { page_opt.cursor = Some(self.get_cursor(cursor)?); } } else { diff --git a/digital_asset_types/src/dao/mod.rs b/digital_asset_types/src/dao/mod.rs index 8e6dc4ecb..4cde6c8b3 100644 --- a/digital_asset_types/src/dao/mod.rs +++ b/digital_asset_types/src/dao/mod.rs @@ -219,11 +219,11 @@ impl SearchAssetsQuery { // In theory, the owner_type=single check should be sufficient, // however there is an old bug that has marked some non-NFTs as "single" with supply > 1. // The supply check guarentees we do not include those. - conditions = conditions.add_option(Some( + conditions = conditions.add( asset::Column::OwnerType .eq(OwnerType::Single) .and(asset::Column::Supply.lte(1)), - )); + ); } } } diff --git a/digital_asset_types/src/dao/scopes/asset.rs b/digital_asset_types/src/dao/scopes/asset.rs index f2113c7f6..924b1e3d8 100644 --- a/digital_asset_types/src/dao/scopes/asset.rs +++ b/digital_asset_types/src/dao/scopes/asset.rs @@ -249,9 +249,7 @@ where .join(JoinType::LeftJoin, relation.def()); if let Some(col) = sort_by { - stmt = stmt - .order_by(col, sort_direction.clone()) - .order_by(asset::Column::Id, sort_direction.clone()); + stmt = stmt.order_by(col, sort_direction.clone()) } let assets = paginate(pagination, limit, stmt, sort_direction, asset::Column::Id) @@ -302,8 +300,7 @@ pub async fn get_related_for_assets( // Get all creators for all assets in `assets_map``. let creators = asset_creators::Entity::find() - .filter(asset_creators::Column::AssetId.is_in(ids)) - .order_by_asc(asset_creators::Column::AssetId) + .filter(asset_creators::Column::AssetId.is_in(ids.clone())) .order_by_asc(asset_creators::Column::Position) .all(conn) .await?; @@ -331,7 +328,6 @@ pub async fn get_related_for_assets( let ids = assets_map.keys().cloned().collect::>(); let authorities = asset_authority::Entity::find() .filter(asset_authority::Column::AssetId.is_in(ids.clone())) - .order_by_asc(asset_authority::Column::AssetId) .all(conn) .await?; for a in authorities.into_iter() { @@ -361,8 +357,7 @@ pub async fn get_related_for_assets( let grouping_base_query = asset_grouping::Entity::find() .filter(asset_grouping::Column::AssetId.is_in(ids.clone())) .filter(asset_grouping::Column::GroupValue.is_not_null()) - .filter(cond) - .order_by_asc(asset_grouping::Column::AssetId); + .filter(cond); if options.show_collection_metadata { let combined_group_query = grouping_base_query @@ -417,9 +412,7 @@ pub async fn get_assets_by_condition( } stmt = stmt.filter(condition); if let Some(col) = sort_by { - stmt = stmt - .order_by(col, sort_direction.clone()) - .order_by(asset::Column::Id, sort_direction.clone()); + stmt = stmt.order_by(col, sort_direction.clone()) } let assets = paginate(pagination, limit, stmt, sort_direction, asset::Column::Id) @@ -462,7 +455,6 @@ pub async fn get_by_id( let (asset, data) = asset_data; let authorities: Vec = asset_authority::Entity::find() .filter(asset_authority::Column::AssetId.eq(asset.id.clone())) - .order_by_asc(asset_authority::Column::AssetId) .all(conn) .await?; let mut creators: Vec = asset_creators::Entity::find() @@ -482,8 +474,7 @@ pub async fn get_by_id( // Older versions of the indexer did not have the verified flag. A group would be present if and only if it was verified. // Therefore if verified is null, we can assume that the group is verified. .add(asset_grouping::Column::Verified.is_null()), - ) - .order_by_asc(asset_grouping::Column::AssetId); + ); let groups = if options.show_collection_metadata { grouping_query @@ -577,7 +568,6 @@ pub async fn get_asset_signatures( let stmt = asset::Entity::find() .distinct_on([(asset::Entity, asset::Column::Id)]) .filter(asset::Column::Id.eq(asset_id)) - .order_by(asset::Column::Id, Order::Desc) .limit(1); let asset = stmt.one(conn).await?; if let Some(asset) = asset { diff --git a/digital_asset_types/src/dapi/common/asset.rs b/digital_asset_types/src/dapi/common/asset.rs index 1ac3c772c..9acd556b2 100644 --- a/digital_asset_types/src/dapi/common/asset.rs +++ b/digital_asset_types/src/dapi/common/asset.rs @@ -127,7 +127,6 @@ pub fn build_transaction_signatures_response( pub fn create_sorting(sorting: AssetSorting) -> (sea_orm::query::Order, Option) { let sort_column = match sorting.sort_by { - AssetSortBy::Id => Some(asset::Column::Id), AssetSortBy::Created => Some(asset::Column::CreatedAt), AssetSortBy::Updated => Some(asset::Column::SlotUpdated), AssetSortBy::RecentAction => Some(asset::Column::SlotUpdated), diff --git a/digital_asset_types/src/rpc/filter.rs b/digital_asset_types/src/rpc/filter.rs index e90b4a158..83416fb8f 100644 --- a/digital_asset_types/src/rpc/filter.rs +++ b/digital_asset_types/src/rpc/filter.rs @@ -12,7 +12,7 @@ pub struct AssetSorting { impl Default for AssetSorting { fn default() -> AssetSorting { AssetSorting { - sort_by: AssetSortBy::Id, + sort_by: AssetSortBy::None, sort_direction: Some(AssetSortDirection::default()), } } @@ -20,8 +20,6 @@ impl Default for AssetSorting { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] pub enum AssetSortBy { - #[serde(rename = "id")] - Id, #[serde(rename = "created")] Created, #[serde(rename = "updated")] diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_authority.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_authority.snap index 53017c8fe..4fb1a6c7c 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_authority.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__mpl_core_tests__mpl_core_get_assets_by_authority.snap @@ -9,14 +9,14 @@ snapshot_kind: text "page": 1, "items": [ { - "interface": "MplCoreAsset", - "id": "4FcFVJVPRsYoMjt8ewDGV5nipoK63SNrJzjrBHyXvhcz", + "interface": "MplCoreCollection", + "id": "9CSyGBw1DCVZfx621nb7UBM9SpVDsX1m9MaN6APCf1Ci", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", - "json_uri": "https://example.com/asset", + "json_uri": "https://example.com/collection", "files": [], "metadata": { - "name": "Test Asset", + "name": "Test Collection", "symbol": "" }, "links": {} @@ -39,12 +39,7 @@ snapshot_kind: text "seq": 0, "leaf_id": 0 }, - "grouping": [ - { - "group_key": "collection", - "group_value": "9CSyGBw1DCVZfx621nb7UBM9SpVDsX1m9MaN6APCf1Ci" - } - ], + "grouping": [], "royalty": { "royalty_model": "creators", "target": null, @@ -59,25 +54,27 @@ snapshot_kind: text "delegated": false, "delegate": null, "ownership_model": "single", - "owner": "GzYvuu9aUYXmnardj4svbAcCNmefiaGu2E3knGw9NJQQ" + "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" }, "mutable": true, "burnt": false, "plugins": {}, "mpl_core_info": { + "num_minted": 1, + "current_size": 1, "plugins_json_version": 1 }, "external_plugins": [] }, { - "interface": "MplCoreCollection", - "id": "9CSyGBw1DCVZfx621nb7UBM9SpVDsX1m9MaN6APCf1Ci", + "interface": "MplCoreAsset", + "id": "4FcFVJVPRsYoMjt8ewDGV5nipoK63SNrJzjrBHyXvhcz", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", - "json_uri": "https://example.com/collection", + "json_uri": "https://example.com/asset", "files": [], "metadata": { - "name": "Test Collection", + "name": "Test Asset", "symbol": "" }, "links": {} @@ -100,7 +97,12 @@ snapshot_kind: text "seq": 0, "leaf_id": 0 }, - "grouping": [], + "grouping": [ + { + "group_key": "collection", + "group_value": "9CSyGBw1DCVZfx621nb7UBM9SpVDsX1m9MaN6APCf1Ci" + } + ], "royalty": { "royalty_model": "creators", "target": null, @@ -115,14 +117,12 @@ snapshot_kind: text "delegated": false, "delegate": null, "ownership_model": "single", - "owner": "APrZTeVysBJqAznfLXS71NAzjr2fCVTSF1A66MeErzM7" + "owner": "GzYvuu9aUYXmnardj4svbAcCNmefiaGu2E3knGw9NJQQ" }, "mutable": true, "burnt": false, "plugins": {}, "mpl_core_info": { - "num_minted": 1, - "current_size": 1, "plugins_json_version": 1 }, "external_plugins": [] diff --git a/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_all.snap b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_all.snap index 6d58cd939..9a0a55094 100644 --- a/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_all.snap +++ b/integration_tests/tests/integration_tests/snapshots/integration_tests__token_type_test__search_asset_with_token_type_all.snap @@ -10,13 +10,13 @@ snapshot_kind: text "items": [ { "interface": "ProgrammableNFT", - "id": "8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo", + "id": "42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", - "json_uri": "https://cdn.hellomoon.io/public/silicons/metadata/1466.json", + "json_uri": "https://cdn.hellomoon.io/public/silicons/metadata/2835.json", "files": [], "metadata": { - "name": "SILICON #1466", + "name": "SILICON #2835", "symbol": "SILI", "token_standard": "ProgrammableNonFungible" }, @@ -78,13 +78,13 @@ snapshot_kind: text }, { "interface": "ProgrammableNFT", - "id": "42AYryUGNmJMe9ycBXZekkYvdTehgbtECHs7SLu5JJTB", + "id": "8t77ShMViat27Sjphvi1FVPaGrhFcttPAkEnLCFp49Bo", "content": { "$schema": "https://schema.metaplex.com/nft1.0.json", - "json_uri": "https://cdn.hellomoon.io/public/silicons/metadata/2835.json", + "json_uri": "https://cdn.hellomoon.io/public/silicons/metadata/1466.json", "files": [], "metadata": { - "name": "SILICON #2835", + "name": "SILICON #1466", "symbol": "SILI", "token_standard": "ProgrammableNonFungible" }, diff --git a/migration/src/lib.rs b/migration/src/lib.rs index 211501cd3..a7468b864 100644 --- a/migration/src/lib.rs +++ b/migration/src/lib.rs @@ -45,6 +45,8 @@ mod m20240320_120101_add_mpl_core_info_items; mod m20240520_120101_add_mpl_core_external_plugins_columns; mod m20240718_161232_change_supply_columns_to_numeric; mod m20241119_060310_add_token_inscription_enum_variant; +mod m20241209_100813_add_unique_index_for_asset_owner_and_supply; +mod m20241209_111604_add_index_for_asset_id_group_value_verified; pub mod model; @@ -99,6 +101,8 @@ impl MigratorTrait for Migrator { Box::new(m20240520_120101_add_mpl_core_external_plugins_columns::Migration), Box::new(m20240718_161232_change_supply_columns_to_numeric::Migration), Box::new(m20241119_060310_add_token_inscription_enum_variant::Migration), + Box::new(m20241209_100813_add_unique_index_for_asset_owner_and_supply::Migration), + Box::new(m20241209_111604_add_index_for_asset_id_group_value_verified::Migration), ] } } diff --git a/migration/src/m20241209_100813_add_unique_index_for_asset_owner_and_supply.rs b/migration/src/m20241209_100813_add_unique_index_for_asset_owner_and_supply.rs new file mode 100644 index 000000000..d7ca68111 --- /dev/null +++ b/migration/src/m20241209_100813_add_unique_index_for_asset_owner_and_supply.rs @@ -0,0 +1,39 @@ +use sea_orm_migration::prelude::*; + +use crate::model::table::Asset; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_index( + Index::create() + .name("idx_asset_owner_supply") + .col(Asset::Owner) + .col(Asset::Supply) + .col(Asset::Burnt) + .col(Asset::OwnerType) + .table(Asset::Table) + .to_owned(), + ) + .await?; + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_index( + Index::drop() + .name("idx_asset_owner_supply") + .table(Asset::Table) + .to_owned(), + ) + .await?; + + Ok(()) + } +} diff --git a/migration/src/m20241209_111604_add_index_for_asset_id_group_value_verified.rs b/migration/src/m20241209_111604_add_index_for_asset_id_group_value_verified.rs new file mode 100644 index 000000000..d23828077 --- /dev/null +++ b/migration/src/m20241209_111604_add_index_for_asset_id_group_value_verified.rs @@ -0,0 +1,38 @@ +use sea_orm_migration::prelude::*; + +use crate::model::table::AssetGrouping; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_index( + Index::create() + .unique() + .name("asset_grouping_id_value_verified_unique") + .col(AssetGrouping::AssetId) + .col(AssetGrouping::GroupValue) + .col(AssetGrouping::Verified) + .table(AssetGrouping::Table) + .to_owned(), + ) + .await?; + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_index( + sea_query::Index::drop() + .name("asset_grouping_id_value_verified_unique") + .table(AssetGrouping::Table) + .to_owned(), + ) + .await?; + + Ok(()) + } +} diff --git a/tools/bgtask_creator/src/main.rs b/tools/bgtask_creator/src/main.rs index 082873da4..0abf32a7c 100644 --- a/tools/bgtask_creator/src/main.rs +++ b/tools/bgtask_creator/src/main.rs @@ -237,7 +237,6 @@ WHERE let mut asset_data_missing = asset_data_processing .0 - .order_by(asset_data::Column::Id, Order::Asc) .paginate(&conn, *batch_size) .into_stream(); @@ -310,11 +309,7 @@ WHERE let condition = asset_data::Column::Reindex.eq(true); let asset_data = find_by_type(authority, collection, creator, mint, condition); - let mut asset_data_missing = asset_data - .0 - .order_by(asset_data::Column::Id, Order::Asc) - .paginate(&conn, *batch_size) - .into_stream(); + let mut asset_data_missing = asset_data.0.paginate(&conn, *batch_size).into_stream(); // Find all the assets with missing metadata let mut tasks = Vec::new();