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}