Skip to content

Commit

Permalink
feat(ark-metadata): collection filters with metadata (#422)
Browse files Browse the repository at this point in the history
## Description

1. add elastic search manager to insert data in elastic search

<!--
Please do not leave this blank.
Describe the changes in this PR. What does it [add/remove/fix/replace]?

For crafting a good description, consider using ChatGPT to help
articulate your changes.
-->

## What type of PR is this? (check all applicable)

- [ ] 🍕 Feature (`feat:`)
- [ ] 🐛 Bug Fix (`fix:`)
- [ ] 📝 Documentation Update (`docs:`)
- [ ] 🎨 Style (`style:`)
- [ ] 🧑‍💻 Code Refactor (`refactor:`)
- [ ] 🔥 Performance Improvements (`perf:`)
- [ ] ✅ Test (`test:`)
- [ ] 🤖 Build (`build:`)
- [ ] 🔁 CI (`ci:`)
- [ ] 📦 Chore (`chore:`)
- [ ] ⏩ Revert (`revert:`)
- [ ] 🚀 Breaking Changes (`BREAKING CHANGE:`)

## Related Tickets & Documents

<!--
Please use this format to link related issues: Fixes #<issue_number>
More info:
https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword
-->

## Added tests?

- [ ] 👍 yes
- [ ] 🙅 no, because they aren't needed
- [ ] 🙋 no, because I need help

## Added to documentation?

- [ ] 📜 README.md
- [ ] 📓 Documentation
- [ ] 🙅 no documentation needed

## [optional] Are there any post-deployment tasks we need to perform?

<!-- Describe any additional tasks, if any, and provide steps. -->

## [optional] What gif best describes this PR or how it makes you feel?

<!-- Share a fun gif related to your PR! -->

### PR Title and Description Guidelines:

- Ensure your PR title follows semantic versioning standards. This helps
automate releases and changelogs.
- Use types like `feat:`, `fix:`, `chore:`, `BREAKING CHANGE:` etc. in
your PR title.
- Your PR title will be used as a commit message when merging. Make sure
it adheres to [Conventional Commits
standards](https://www.conventionalcommits.org/).

## Closing Issues

<!--
Use keywords to close related issues. This ensures that the associated
issues will automatically close when the PR is merged.

- `Fixes #123` will close issue 123 when the PR is merged.
- `Closes #123` will also close issue 123 when the PR is merged.
- `Resolves #123` will also close issue 123 when the PR is merged.

You can also use multiple keywords in one comment:
- `Fixes #123, Resolves #456`

More info:
https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue
-->
  • Loading branch information
ybensacq authored Aug 22, 2024
1 parent 125c378 commit df63d8e
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 16 deletions.
17 changes: 17 additions & 0 deletions crates/ark-metadata/src/elasticsearch_manager.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use crate::types::{RequestError, TokenMetadata};
use async_trait::async_trait;

#[cfg(any(test, feature = "mock"))]
use mockall::automock;

#[cfg_attr(any(test, feature = "mock"), automock)]
#[async_trait]
pub trait ElasticsearchManager {
async fn upsert_token_metadata(
&self,
contract_address: &str,
token_id: &str,
chain_id: &str,
metadata: TokenMetadata,
) -> Result<(), RequestError>;
}
1 change: 1 addition & 0 deletions crates/ark-metadata/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod elasticsearch_manager;
pub mod file_manager;
pub mod metadata_manager;
pub mod storage;
Expand Down
73 changes: 65 additions & 8 deletions crates/ark-metadata/src/metadata_manager.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{
elasticsearch_manager::ElasticsearchManager,
file_manager::{FileInfo, FileManager},
storage::Storage,
types::StorageError,
Expand All @@ -18,11 +19,18 @@ use tracing::{debug, error, trace};

/// `MetadataManager` is responsible for managing metadata information related to tokens.
/// It works with the underlying storage and Starknet client to fetch and update token metadata.
pub struct MetadataManager<'a, T: Storage, C: StarknetClient, F: FileManager> {
pub struct MetadataManager<
'a,
T: Storage,
C: StarknetClient,
F: FileManager,
E: ElasticsearchManager,
> {
storage: &'a T,
starknet_client: &'a C,
request_client: ReqwestClient,
file_manager: &'a F,
elasticsearch_manager: &'a E,
}

pub struct MetadataMedia {
Expand All @@ -38,6 +46,9 @@ pub enum MetadataError {
#[error("Database operation failed: {0}")]
DatabaseError(StorageError),

#[error("ElasticSearch operation failed: {0}")]
ElasticSearchError(String),

#[error("Failed to parse data: {0}")]
ParsingError(String),

Expand All @@ -51,14 +62,22 @@ pub enum MetadataError {
EnvVarMissingError(String),
}

impl<'a, T: Storage, C: StarknetClient, F: FileManager> MetadataManager<'a, T, C, F> {
impl<'a, T: Storage, C: StarknetClient, F: FileManager, E: ElasticsearchManager>
MetadataManager<'a, T, C, F, E>
{
/// Creates a new instance of `MetadataManager` with the given storage, Starknet client, and a new request client.
pub fn new(storage: &'a T, starknet_client: &'a C, file_manager: &'a F) -> Self {
pub fn new(
storage: &'a T,
starknet_client: &'a C,
file_manager: &'a F,
elasticsearch_manager: &'a E,
) -> Self {
MetadataManager {
storage,
starknet_client,
request_client: ReqwestClient::new(),
file_manager,
elasticsearch_manager,
}
}

Expand Down Expand Up @@ -162,10 +181,15 @@ impl<'a, T: Storage, C: StarknetClient, F: FileManager> MetadataManager<'a, T, C
}

self.storage
.register_token_metadata(contract_address, token_id, chain_id, token_metadata)
.register_token_metadata(contract_address, token_id, chain_id, token_metadata.clone())
.await
.map_err(MetadataError::DatabaseError)?;

self.elasticsearch_manager
.upsert_token_metadata(contract_address, token_id, chain_id, token_metadata)
.await
.map_err(|e| MetadataError::ElasticSearchError(e.to_string()))?;

Ok(())
}

Expand Down Expand Up @@ -419,7 +443,10 @@ impl<'a, T: Storage, C: StarknetClient, F: FileManager> MetadataManager<'a, T, C
mod tests {
use super::*;

use crate::{file_manager::MockFileManager, storage::MockStorage, types::TokenWithoutMetadata};
use crate::{
elasticsearch_manager::MockElasticsearchManager, file_manager::MockFileManager,
storage::MockStorage, types::TokenWithoutMetadata,
};
use ark_starknet::client::MockStarknetClient;
use mockall::predicate::*;
use reqwest::header::HeaderMap;
Expand Down Expand Up @@ -450,6 +477,7 @@ mod tests {
let mut mock_client = MockStarknetClient::default();
let storage_manager = MockStorage::default();
let mock_file = MockFileManager::default();
let mock_elasticsearch_manager = MockElasticsearchManager::default();

mock_client
.expect_call_contract()
Expand All @@ -464,7 +492,12 @@ mod tests {
])
});

let mut metadata_manager = MetadataManager::new(&storage_manager, &mock_client, &mock_file);
let mut metadata_manager = MetadataManager::new(
&storage_manager,
&mock_client,
&mock_file,
&mock_elasticsearch_manager,
);

// EXECUTION: Call the function under test
let result = metadata_manager
Expand All @@ -483,6 +516,7 @@ mod tests {
let mut mock_client = MockStarknetClient::default();
let mut mock_storage = MockStorage::default();
let mock_file = MockFileManager::default();
let mut mock_elasticsearch_manager = MockElasticsearchManager::default();

let contract_address = "0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8";
let ipfs_gateway_uri = "https://ipfs.example.com";
Expand Down Expand Up @@ -510,6 +544,18 @@ mod tests {
}])
});

mock_elasticsearch_manager
.expect_upsert_token_metadata()
.times(1)
.withf(move |contract_addr, token_id, chain_id, metadata| {
contract_addr
== "0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8"
&& token_id == "1"
&& chain_id == "0x534e5f4d41494e"
&& metadata.normalized.name.is_none()
})
.returning(|_, _, _, _| Ok(()));

mock_client
.expect_call_contract()
.times(1)
Expand All @@ -530,7 +576,12 @@ mod tests {
.with(always(), always(), always(), always())
.returning(|_, _, _, _| Ok(()));

let mut metadata_manager = MetadataManager::new(&mock_storage, &mock_client, &mock_file);
let mut metadata_manager = MetadataManager::new(
&mock_storage,
&mock_client,
&mock_file,
&mock_elasticsearch_manager,
);

// EXECUTION: Call the function under test
let result = metadata_manager
Expand All @@ -552,6 +603,7 @@ mod tests {
// SETUP: Mocking and Initializing
let mut mock_client = MockStarknetClient::default();
let mock_file = MockFileManager::default();
let mock_elasticsearch_manager = MockElasticsearchManager::default();

let contract_address = FieldElement::ONE;
let selector_name = selector!("tokenURI");
Expand All @@ -577,7 +629,12 @@ mod tests {
});

let storage_manager = MockStorage::default();
let mut metadata_manager = MetadataManager::new(&storage_manager, &mock_client, &mock_file);
let mut metadata_manager = MetadataManager::new(
&storage_manager,
&mock_client,
&mock_file,
&mock_elasticsearch_manager,
);

// EXECUTION: Call the function under test
let result = metadata_manager
Expand Down
12 changes: 12 additions & 0 deletions crates/ark-metadata/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,15 @@ pub struct MetadataProperty {
property_type: String,
description: String,
}

#[derive(Debug, thiserror::Error)]
pub enum RequestError {
#[error("Request error: {0}")]
Reqwest(String),
}

impl From<reqwest::Error> for RequestError {
fn from(error: reqwest::Error) -> Self {
RequestError::Reqwest(error.to_string())
}
}
14 changes: 6 additions & 8 deletions packages/core/src/contracts.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
// This file is auto-generated. Do not edit directly.

export const SEPOLIA_CONTRACTS = {
messaging:
"0x74f13f1dffb5ad3c051d535ba03514e653b6dcac68e30b2db66a0aa0217c815",
executor: "0xb86ab357c15c12fb78f9b0a19fa974c730fcbab96f17881827dde871665f0b",
orderbook: "0x795b605fa3144afd6f11a4499f71b9cf373bcba3f1b2835d51f65ab59392261"
"messaging": "0x74f13f1dffb5ad3c051d535ba03514e653b6dcac68e30b2db66a0aa0217c815",
"executor": "0xb86ab357c15c12fb78f9b0a19fa974c730fcbab96f17881827dde871665f0b",
"orderbook": "0x795b605fa3144afd6f11a4499f71b9cf373bcba3f1b2835d51f65ab59392261"
};
export const MAINNET_CONTRACTS = {
messaging:
"0x57d45cc46de463f7ae63b74ce9b6b6b496a1178b02e7ad04d7c307caa698b7b",
executor: "0x7b42945bc47001db92fe1b9739d753925263f2f1036c2ae1f87536c916ee6a",
orderbook: "0x5add3084bb8664eb2a641cf26a28f60588c3ccd63af0632aafefcbb2332c345"
"messaging": "0x57d45cc46de463f7ae63b74ce9b6b6b496a1178b02e7ad04d7c307caa698b7b",
"executor": "0x7b42945bc47001db92fe1b9739d753925263f2f1036c2ae1f87536c916ee6a",
"orderbook": "0x5add3084bb8664eb2a641cf26a28f60588c3ccd63af0632aafefcbb2332c345"
};

0 comments on commit df63d8e

Please sign in to comment.