provwasm_stdv1/
querier.rs

1use cosmwasm_std::{from_binary, Addr, QuerierWrapper, StdError, StdResult};
2use serde::de::DeserializeOwned;
3
4use crate::common::{validate_address, validate_string};
5use crate::query::{
6    AttributeQueryParams, MarkerQueryParams, MetadataQueryParams, NameQueryParams, ProvenanceQuery,
7    ProvenanceQueryParams,
8};
9use crate::types::{
10    AttributeValueType, Attributes, Marker, Name, Names, ProvenanceRoute, Record, Records, Scope,
11    Sessions,
12};
13
14// The data format version to pass into provenance for queries.
15static QUERY_DATAFMT_VERSION: &str = "2.0.0";
16
17/// A type for simplifying provenance custom queries.
18pub struct ProvenanceQuerier<'a> {
19    querier: &'a QuerierWrapper<'a, ProvenanceQuery>,
20}
21
22impl<'a> ProvenanceQuerier<'a> {
23    /// Creates a new provenance querier
24    pub fn new(querier: &'a QuerierWrapper<'a, ProvenanceQuery>) -> Self {
25        ProvenanceQuerier { querier }
26    }
27
28    // Execute a name module query.
29    fn query_name_module(&self, params: NameQueryParams) -> StdResult<Names> {
30        let request = ProvenanceQuery {
31            route: ProvenanceRoute::Name,
32            params: ProvenanceQueryParams::Name(params),
33            version: String::from(QUERY_DATAFMT_VERSION),
34        };
35        let res: Names = self.querier.query(&request.into())?;
36        Ok(res)
37    }
38
39    /// Resolve the address for a name.
40    ///
41    /// ### Example
42    ///
43    /// ```rust
44    /// // Imports required
45    /// use cosmwasm_std::{Deps, QueryResponse, StdResult};
46    /// use provwasm_std::{Name, ProvenanceQuerier, ProvenanceQuery};
47    ///
48    /// // Resolve the address for a name.
49    /// fn query_resolve_name(deps: Deps<ProvenanceQuery>, name: String) -> StdResult<QueryResponse> {
50    ///     let querier = ProvenanceQuerier::new(&deps.querier);
51    ///     let name: Name = querier.resolve_name(&name)?;
52    ///     // Do something with name.address ...
53    ///     todo!()
54    /// }
55    /// ```
56    pub fn resolve_name<S: Into<String>>(&self, name: S) -> StdResult<Name> {
57        let res = self.query_name_module(NameQueryParams::Resolve {
58            name: validate_string(name, "name")?,
59        })?;
60        if res.records.len() != 1 {
61            return Err(StdError::generic_err(
62                "expected only one address bound to name",
63            ));
64        }
65        Ok(res.records[0].clone())
66    }
67
68    /// Lookup all names bound to the given address.
69    ///
70    /// ### Example
71    ///
72    /// ```rust
73    /// // Imports required
74    /// use cosmwasm_std::{Addr, Deps, QueryResponse, StdResult};
75    /// use provwasm_std::{Names, ProvenanceQuerier, ProvenanceQuery};
76    ///
77    /// // Lookup all names bound to an address.
78    /// fn query_lookup_names(deps: Deps<ProvenanceQuery>, address: Addr) -> StdResult<QueryResponse> {
79    ///     let querier = ProvenanceQuerier::new(&deps.querier);
80    ///     let names: Names = querier.lookup_names(address)?;
81    ///     // Do something with names.records ...
82    ///     todo!()
83    /// }
84    /// ```
85    pub fn lookup_names<H: Into<Addr>>(&self, address: H) -> StdResult<Names> {
86        self.query_name_module(NameQueryParams::Lookup {
87            address: validate_address(address)?,
88        })
89    }
90
91    // Execute a attribute module query.
92    fn query_attributes(&self, params: AttributeQueryParams) -> StdResult<Attributes> {
93        let request = ProvenanceQuery {
94            route: ProvenanceRoute::Attribute,
95            params: ProvenanceQueryParams::Attribute(params),
96            version: String::from(QUERY_DATAFMT_VERSION),
97        };
98        let res: Attributes = self.querier.query(&request.into())?;
99        Ok(res)
100    }
101
102    /// Get attributes for an account. If the name parameter is `None`, all attributes are returned.
103    ///
104    ///  ### Example
105    ///
106    /// ```rust
107    /// // Imports required
108    /// use cosmwasm_std::{Addr, Deps, QueryResponse, StdResult};
109    /// use provwasm_std::{Attributes, ProvenanceQuerier, ProvenanceQuery};
110    ///
111    /// // Query all attributes added to an account.
112    /// pub fn try_query_attributes(deps: Deps<ProvenanceQuery>, address: Addr) -> StdResult<QueryResponse> {
113    ///     let querier = ProvenanceQuerier::new(&deps.querier);
114    ///     let none: Option<String> = None;
115    ///     let res: Attributes = querier.get_attributes(address, none)?;
116    ///     // Do something with res.attributes ...
117    ///     todo!()
118    /// }
119    /// ```
120    pub fn get_attributes<H: Into<Addr>, S: Into<String>>(
121        &self,
122        address: H,
123        name: Option<S>,
124    ) -> StdResult<Attributes> {
125        let address = validate_address(address)?;
126        match name {
127            None => self.query_attributes(AttributeQueryParams::GetAllAttributes { address }),
128            Some(name) => self.query_attributes(AttributeQueryParams::GetAttributes {
129                address,
130                name: validate_string(name, "name")?,
131            }),
132        }
133    }
134
135    /// Get named JSON attributes from an account and deserialize the values.
136    /// Attribute values with the same name must be able to be deserialized to the same type.
137    ///
138    /// ### Example
139    ///
140    /// ```rust
141    /// // Imports required
142    /// use cosmwasm_std::{Addr, Deps, QueryResponse, StdResult};
143    /// use provwasm_std::{ProvenanceQuerier, ProvenanceQuery};
144    /// use schemars::JsonSchema;
145    /// use serde::{Deserialize, Serialize};
146    ///
147    /// // Query all label attributes added to an account.
148    /// pub fn query_labels(deps: Deps<ProvenanceQuery>, address: Addr) -> StdResult<QueryResponse> {
149    ///     let attr_name = String::from("label.my-contract.sc.pb");
150    ///     let querier = ProvenanceQuerier::new(&deps.querier);
151    ///     let labels: Vec<Label> = querier.get_json_attributes(address, &attr_name)?;
152    ///     // Do something with labels...
153    ///     todo!()
154    /// }
155    ///
156    /// // Text with timestamp.
157    /// #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema)]
158    /// #[serde(rename_all = "snake_case")]
159    /// pub struct Label {
160    ///     pub text: String,
161    ///     pub timestamp: u64,
162    /// }
163    /// ```
164    pub fn get_json_attributes<H: Into<Addr>, S: Into<String>, T: DeserializeOwned>(
165        &self,
166        address: H,
167        name: S,
168    ) -> StdResult<Vec<T>> {
169        // Gather results
170        let resp = self.query_attributes(AttributeQueryParams::GetAttributes {
171            address: validate_address(address)?,
172            name: validate_string(name, "name")?,
173        })?;
174        // Map deserialize, returning values or failure.
175        resp.attributes
176            .iter()
177            .filter(|a| a.value_type == AttributeValueType::Json)
178            .map(|a| from_binary(&a.value))
179            .collect()
180    }
181
182    // Execute a marker module query.
183    fn query_marker(&self, params: MarkerQueryParams) -> StdResult<Marker> {
184        let request = ProvenanceQuery {
185            route: ProvenanceRoute::Marker,
186            params: ProvenanceQueryParams::Marker(params),
187            version: String::from(QUERY_DATAFMT_VERSION),
188        };
189        let res: Marker = self.querier.query(&request.into())?;
190        Ok(res)
191    }
192
193    /// Get a marker by address.
194    ///
195    /// ### Example
196    ///
197    /// ```rust
198    /// // Imports required
199    /// use provwasm_std::{ProvenanceQuerier, Marker, ProvenanceQuery};
200    /// use cosmwasm_std::{Addr, Deps, QueryResponse, StdResult};
201    ///
202    /// // Query a marker by address.
203    /// fn try_get_marker_by_address(deps: Deps<ProvenanceQuery>, address: Addr) -> StdResult<QueryResponse> {
204    ///     let querier = ProvenanceQuerier::new(&deps.querier);
205    ///     let marker: Marker = querier.get_marker_by_address(address)?;
206    ///     // Do something with marker ...
207    ///     todo!()
208    /// }
209    /// ```
210    pub fn get_marker_by_address<H: Into<Addr>>(&self, address: H) -> StdResult<Marker> {
211        self.query_marker(MarkerQueryParams::GetMarkerByAddress {
212            address: validate_address(address)?,
213        })
214    }
215
216    /// Get a marker by denomination.
217    ///
218    /// ### Example
219    ///
220    /// ```rust
221    /// // Imports required
222    /// use cosmwasm_std::{Deps, QueryResponse, StdResult};
223    /// use provwasm_std::{ProvenanceQuerier, Marker, ProvenanceQuery};
224    ///
225    /// // Query a marker by denom.
226    /// fn try_get_marker_by_denom(deps: Deps<ProvenanceQuery>, denom: String) -> StdResult<QueryResponse> {
227    ///     let querier = ProvenanceQuerier::new(&deps.querier);
228    ///     let marker: Marker = querier.get_marker_by_denom(&denom)?;
229    ///     // Do something with marker ...
230    ///     todo!()
231    /// }
232    /// ```
233    pub fn get_marker_by_denom<S: Into<String>>(&self, denom: S) -> StdResult<Marker> {
234        self.query_marker(MarkerQueryParams::GetMarkerByDenom {
235            denom: validate_string(denom, "denom")?,
236        })
237    }
238
239    // Execute a scope query against the metadata module.
240    fn query_scope(&self, params: MetadataQueryParams) -> StdResult<Scope> {
241        let request = ProvenanceQuery {
242            route: ProvenanceRoute::Metadata,
243            params: ProvenanceQueryParams::Metadata(params),
244            version: String::from(QUERY_DATAFMT_VERSION),
245        };
246        let res: Scope = self.querier.query(&request.into())?;
247        Ok(res)
248    }
249
250    /// Get a scope by metadata ID (bech32 address string).
251    ///
252    /// ### Example
253    /// ```rust
254    /// // Imports required
255    /// use provwasm_std::{ProvenanceQuerier, ProvenanceQuery, Scope};
256    /// use cosmwasm_std::{Deps, QueryResponse, StdResult};
257    ///
258    /// // Query a scope by id.
259    /// fn try_get_scope(deps: Deps<ProvenanceQuery>, scope_id: String) -> StdResult<QueryResponse> {
260    ///     let querier = ProvenanceQuerier::new(&deps.querier);
261    ///     let scope: Scope = querier.get_scope(scope_id)?;
262    ///     // Do something with scope ...
263    ///     todo!()
264    /// }
265    /// ```
266    pub fn get_scope<S: Into<String>>(&self, scope_id: S) -> StdResult<Scope> {
267        self.query_scope(MetadataQueryParams::GetScope {
268            scope_id: validate_string(scope_id, "scope_id")?,
269        })
270    }
271
272    // Execute a sessions query against the metadata module.
273    fn query_sessions(&self, params: MetadataQueryParams) -> StdResult<Sessions> {
274        let request = ProvenanceQuery {
275            route: ProvenanceRoute::Metadata,
276            params: ProvenanceQueryParams::Metadata(params),
277            version: String::from(QUERY_DATAFMT_VERSION),
278        };
279        let res: Sessions = self.querier.query(&request.into())?;
280        Ok(res)
281    }
282
283    /// Get all scope sessions.
284    ///
285    /// ### Example
286    /// ```rust
287    /// // Imports required
288    /// use provwasm_std::{ProvenanceQuerier, ProvenanceQuery, Sessions};
289    /// use cosmwasm_std::{Deps, QueryResponse, StdResult};
290    ///
291    /// // Query all sessions for a scope.
292    /// fn try_get_sessions(deps: Deps<ProvenanceQuery>, scope_id: String) -> StdResult<QueryResponse> {
293    ///     let querier = ProvenanceQuerier::new(&deps.querier);
294    ///     let res: Sessions = querier.get_sessions(scope_id)?;
295    ///     // Do something with res.sessions ...
296    ///     todo!()
297    /// }
298    /// ```
299    pub fn get_sessions<S: Into<String>>(&self, scope_id: S) -> StdResult<Sessions> {
300        let scope_id = validate_string(scope_id, "scope_id")?;
301        self.query_sessions(MetadataQueryParams::GetSessions { scope_id })
302    }
303
304    // Execute a record query against the metadata module.
305    fn query_records(&self, params: MetadataQueryParams) -> StdResult<Records> {
306        let request = ProvenanceQuery {
307            route: ProvenanceRoute::Metadata,
308            params: ProvenanceQueryParams::Metadata(params),
309            version: String::from(QUERY_DATAFMT_VERSION),
310        };
311        let res: Records = self.querier.query(&request.into())?;
312        Ok(res)
313    }
314
315    /// Get all scope records.
316    ///
317    /// ### Example
318    /// ```rust
319    /// // Imports required
320    /// use provwasm_std::{ProvenanceQuerier, ProvenanceQuery, Records};
321    /// use cosmwasm_std::{Deps, QueryResponse, StdResult};
322    ///
323    /// // Query all records for a scope.
324    /// fn try_get_records(deps: Deps<ProvenanceQuery>, scope_id: String) -> StdResult<QueryResponse> {
325    ///     let querier = ProvenanceQuerier::new(&deps.querier);
326    ///     let res: Records = querier.get_records(scope_id)?;
327    ///     // Do something with res.records ...
328    ///     todo!()
329    /// }
330    /// ```
331    pub fn get_records<S: Into<String>>(&self, scope_id: S) -> StdResult<Records> {
332        let scope_id = validate_string(scope_id, "scope_id")?;
333        let name: Option<String> = None;
334        self.query_records(MetadataQueryParams::GetRecords { scope_id, name })
335    }
336
337    /// Get a scope record with the given name.
338    ///
339    /// ### Example
340    /// ```rust
341    /// // Imports required
342    /// use provwasm_std::{ProvenanceQuerier, ProvenanceQuery, Record};
343    /// use cosmwasm_std::{Deps, QueryResponse, StdResult};
344    ///
345    /// // Query a loan record for a scope.
346    /// fn try_get_loan_record(deps: Deps<ProvenanceQuery>, scope_id: String) -> StdResult<QueryResponse> {
347    ///     let querier = ProvenanceQuerier::new(&deps.querier);
348    ///     let record: Record = querier.get_record_by_name(scope_id, "loan")?;
349    ///     // Do something with record ...
350    ///     todo!()
351    /// }
352    /// ```
353    pub fn get_record_by_name<S: Into<String>, T: Into<String>>(
354        &self,
355        scope_id: S,
356        name: T,
357    ) -> StdResult<Record> {
358        let scope_id = validate_string(scope_id, "scope_id")?;
359        let name: String = validate_string(name, "name")?;
360        let res = self.query_records(MetadataQueryParams::GetRecords {
361            scope_id,
362            name: Some(name.clone()),
363        })?;
364        if res.records.is_empty() {
365            return Err(StdError::not_found(format!("record not found: {}", name)));
366        }
367        Ok(res.records[0].clone())
368    }
369}