1use std::collections::HashMap;
50
51use chrono::{DateTime, Utc};
52use serde::{Deserialize, Serialize};
53
54use crate::clients::RestClient;
55use crate::rest::{
56 build_path, ResourceError, ResourceOperation, ResourcePath, ResourceResponse, RestResource,
57};
58use crate::HttpMethod;
59
60use super::common::MetafieldOwner;
61
62#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
101pub struct Metafield {
102 #[serde(skip_serializing)]
105 pub id: Option<u64>,
106
107 #[serde(skip_serializing_if = "Option::is_none")]
112 pub namespace: Option<String>,
113
114 #[serde(skip_serializing_if = "Option::is_none")]
118 pub key: Option<String>,
119
120 #[serde(skip_serializing_if = "Option::is_none")]
124 pub value: Option<String>,
125
126 #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
131 pub metafield_type: Option<String>,
132
133 #[serde(skip_serializing)]
136 pub owner_id: Option<u64>,
137
138 #[serde(skip_serializing)]
143 pub owner_resource: Option<String>,
144
145 #[serde(skip_serializing_if = "Option::is_none")]
147 pub description: Option<String>,
148
149 #[serde(skip_serializing)]
152 pub created_at: Option<DateTime<Utc>>,
153
154 #[serde(skip_serializing)]
157 pub updated_at: Option<DateTime<Utc>>,
158
159 #[serde(skip_serializing)]
162 pub admin_graphql_api_id: Option<String>,
163}
164
165impl RestResource for Metafield {
166 type Id = u64;
167 type FindParams = MetafieldFindParams;
168 type AllParams = MetafieldListParams;
169 type CountParams = MetafieldCountParams;
170
171 const NAME: &'static str = "Metafield";
172 const PLURAL: &'static str = "metafields";
173
174 const PATHS: &'static [ResourcePath] = &[
191 ResourcePath::new(
193 HttpMethod::Get,
194 ResourceOperation::Find,
195 &["product_id", "id"],
196 "products/{product_id}/metafields/{id}",
197 ),
198 ResourcePath::new(
199 HttpMethod::Get,
200 ResourceOperation::All,
201 &["product_id"],
202 "products/{product_id}/metafields",
203 ),
204 ResourcePath::new(
205 HttpMethod::Get,
206 ResourceOperation::Count,
207 &["product_id"],
208 "products/{product_id}/metafields/count",
209 ),
210 ResourcePath::new(
211 HttpMethod::Post,
212 ResourceOperation::Create,
213 &["product_id"],
214 "products/{product_id}/metafields",
215 ),
216 ResourcePath::new(
217 HttpMethod::Put,
218 ResourceOperation::Update,
219 &["product_id", "id"],
220 "products/{product_id}/metafields/{id}",
221 ),
222 ResourcePath::new(
223 HttpMethod::Delete,
224 ResourceOperation::Delete,
225 &["product_id", "id"],
226 "products/{product_id}/metafields/{id}",
227 ),
228 ResourcePath::new(
230 HttpMethod::Get,
231 ResourceOperation::Find,
232 &["variant_id", "id"],
233 "variants/{variant_id}/metafields/{id}",
234 ),
235 ResourcePath::new(
236 HttpMethod::Get,
237 ResourceOperation::All,
238 &["variant_id"],
239 "variants/{variant_id}/metafields",
240 ),
241 ResourcePath::new(
242 HttpMethod::Get,
243 ResourceOperation::Count,
244 &["variant_id"],
245 "variants/{variant_id}/metafields/count",
246 ),
247 ResourcePath::new(
248 HttpMethod::Post,
249 ResourceOperation::Create,
250 &["variant_id"],
251 "variants/{variant_id}/metafields",
252 ),
253 ResourcePath::new(
254 HttpMethod::Put,
255 ResourceOperation::Update,
256 &["variant_id", "id"],
257 "variants/{variant_id}/metafields/{id}",
258 ),
259 ResourcePath::new(
260 HttpMethod::Delete,
261 ResourceOperation::Delete,
262 &["variant_id", "id"],
263 "variants/{variant_id}/metafields/{id}",
264 ),
265 ResourcePath::new(
267 HttpMethod::Get,
268 ResourceOperation::Find,
269 &["customer_id", "id"],
270 "customers/{customer_id}/metafields/{id}",
271 ),
272 ResourcePath::new(
273 HttpMethod::Get,
274 ResourceOperation::All,
275 &["customer_id"],
276 "customers/{customer_id}/metafields",
277 ),
278 ResourcePath::new(
279 HttpMethod::Get,
280 ResourceOperation::Count,
281 &["customer_id"],
282 "customers/{customer_id}/metafields/count",
283 ),
284 ResourcePath::new(
285 HttpMethod::Post,
286 ResourceOperation::Create,
287 &["customer_id"],
288 "customers/{customer_id}/metafields",
289 ),
290 ResourcePath::new(
291 HttpMethod::Put,
292 ResourceOperation::Update,
293 &["customer_id", "id"],
294 "customers/{customer_id}/metafields/{id}",
295 ),
296 ResourcePath::new(
297 HttpMethod::Delete,
298 ResourceOperation::Delete,
299 &["customer_id", "id"],
300 "customers/{customer_id}/metafields/{id}",
301 ),
302 ResourcePath::new(
304 HttpMethod::Get,
305 ResourceOperation::Find,
306 &["order_id", "id"],
307 "orders/{order_id}/metafields/{id}",
308 ),
309 ResourcePath::new(
310 HttpMethod::Get,
311 ResourceOperation::All,
312 &["order_id"],
313 "orders/{order_id}/metafields",
314 ),
315 ResourcePath::new(
316 HttpMethod::Get,
317 ResourceOperation::Count,
318 &["order_id"],
319 "orders/{order_id}/metafields/count",
320 ),
321 ResourcePath::new(
322 HttpMethod::Post,
323 ResourceOperation::Create,
324 &["order_id"],
325 "orders/{order_id}/metafields",
326 ),
327 ResourcePath::new(
328 HttpMethod::Put,
329 ResourceOperation::Update,
330 &["order_id", "id"],
331 "orders/{order_id}/metafields/{id}",
332 ),
333 ResourcePath::new(
334 HttpMethod::Delete,
335 ResourceOperation::Delete,
336 &["order_id", "id"],
337 "orders/{order_id}/metafields/{id}",
338 ),
339 ResourcePath::new(
341 HttpMethod::Get,
342 ResourceOperation::Find,
343 &["collection_id", "id"],
344 "collections/{collection_id}/metafields/{id}",
345 ),
346 ResourcePath::new(
347 HttpMethod::Get,
348 ResourceOperation::All,
349 &["collection_id"],
350 "collections/{collection_id}/metafields",
351 ),
352 ResourcePath::new(
353 HttpMethod::Get,
354 ResourceOperation::Count,
355 &["collection_id"],
356 "collections/{collection_id}/metafields/count",
357 ),
358 ResourcePath::new(
359 HttpMethod::Post,
360 ResourceOperation::Create,
361 &["collection_id"],
362 "collections/{collection_id}/metafields",
363 ),
364 ResourcePath::new(
365 HttpMethod::Put,
366 ResourceOperation::Update,
367 &["collection_id", "id"],
368 "collections/{collection_id}/metafields/{id}",
369 ),
370 ResourcePath::new(
371 HttpMethod::Delete,
372 ResourceOperation::Delete,
373 &["collection_id", "id"],
374 "collections/{collection_id}/metafields/{id}",
375 ),
376 ResourcePath::new(
378 HttpMethod::Get,
379 ResourceOperation::Find,
380 &["page_id", "id"],
381 "pages/{page_id}/metafields/{id}",
382 ),
383 ResourcePath::new(
384 HttpMethod::Get,
385 ResourceOperation::All,
386 &["page_id"],
387 "pages/{page_id}/metafields",
388 ),
389 ResourcePath::new(
390 HttpMethod::Get,
391 ResourceOperation::Count,
392 &["page_id"],
393 "pages/{page_id}/metafields/count",
394 ),
395 ResourcePath::new(
396 HttpMethod::Post,
397 ResourceOperation::Create,
398 &["page_id"],
399 "pages/{page_id}/metafields",
400 ),
401 ResourcePath::new(
402 HttpMethod::Put,
403 ResourceOperation::Update,
404 &["page_id", "id"],
405 "pages/{page_id}/metafields/{id}",
406 ),
407 ResourcePath::new(
408 HttpMethod::Delete,
409 ResourceOperation::Delete,
410 &["page_id", "id"],
411 "pages/{page_id}/metafields/{id}",
412 ),
413 ResourcePath::new(
415 HttpMethod::Get,
416 ResourceOperation::Find,
417 &["blog_id", "id"],
418 "blogs/{blog_id}/metafields/{id}",
419 ),
420 ResourcePath::new(
421 HttpMethod::Get,
422 ResourceOperation::All,
423 &["blog_id"],
424 "blogs/{blog_id}/metafields",
425 ),
426 ResourcePath::new(
427 HttpMethod::Get,
428 ResourceOperation::Count,
429 &["blog_id"],
430 "blogs/{blog_id}/metafields/count",
431 ),
432 ResourcePath::new(
433 HttpMethod::Post,
434 ResourceOperation::Create,
435 &["blog_id"],
436 "blogs/{blog_id}/metafields",
437 ),
438 ResourcePath::new(
439 HttpMethod::Put,
440 ResourceOperation::Update,
441 &["blog_id", "id"],
442 "blogs/{blog_id}/metafields/{id}",
443 ),
444 ResourcePath::new(
445 HttpMethod::Delete,
446 ResourceOperation::Delete,
447 &["blog_id", "id"],
448 "blogs/{blog_id}/metafields/{id}",
449 ),
450 ResourcePath::new(
452 HttpMethod::Get,
453 ResourceOperation::Find,
454 &["article_id", "id"],
455 "articles/{article_id}/metafields/{id}",
456 ),
457 ResourcePath::new(
458 HttpMethod::Get,
459 ResourceOperation::All,
460 &["article_id"],
461 "articles/{article_id}/metafields",
462 ),
463 ResourcePath::new(
464 HttpMethod::Get,
465 ResourceOperation::Count,
466 &["article_id"],
467 "articles/{article_id}/metafields/count",
468 ),
469 ResourcePath::new(
470 HttpMethod::Post,
471 ResourceOperation::Create,
472 &["article_id"],
473 "articles/{article_id}/metafields",
474 ),
475 ResourcePath::new(
476 HttpMethod::Put,
477 ResourceOperation::Update,
478 &["article_id", "id"],
479 "articles/{article_id}/metafields/{id}",
480 ),
481 ResourcePath::new(
482 HttpMethod::Delete,
483 ResourceOperation::Delete,
484 &["article_id", "id"],
485 "articles/{article_id}/metafields/{id}",
486 ),
487 ResourcePath::new(HttpMethod::Get, ResourceOperation::All, &[], "metafields"),
490 ResourcePath::new(
491 HttpMethod::Get,
492 ResourceOperation::Count,
493 &[],
494 "metafields/count",
495 ),
496 ResourcePath::new(
497 HttpMethod::Post,
498 ResourceOperation::Create,
499 &[],
500 "metafields",
501 ),
502 ResourcePath::new(
504 HttpMethod::Get,
505 ResourceOperation::Find,
506 &["id"],
507 "metafields/{id}",
508 ),
509 ResourcePath::new(
510 HttpMethod::Put,
511 ResourceOperation::Update,
512 &["id"],
513 "metafields/{id}",
514 ),
515 ResourcePath::new(
516 HttpMethod::Delete,
517 ResourceOperation::Delete,
518 &["id"],
519 "metafields/{id}",
520 ),
521 ];
522
523 fn get_id(&self) -> Option<Self::Id> {
524 self.id
525 }
526}
527
528impl Metafield {
529 pub async fn all_for_owner(
584 client: &RestClient,
585 owner: MetafieldOwner,
586 owner_id: u64,
587 params: Option<MetafieldListParams>,
588 ) -> Result<ResourceResponse<Vec<Self>>, ResourceError> {
589 let parent_id_name = match owner {
591 MetafieldOwner::Product => "product_id",
592 MetafieldOwner::Variant => "variant_id",
593 MetafieldOwner::Customer => "customer_id",
594 MetafieldOwner::Order => "order_id",
595 MetafieldOwner::Collection => "collection_id",
596 MetafieldOwner::Page => "page_id",
597 MetafieldOwner::Blog => "blog_id",
598 MetafieldOwner::Article => "article_id",
599 MetafieldOwner::Shop => {
600 return Self::all(client, params).await;
602 }
603 };
604
605 Self::all_with_parent(client, parent_id_name, owner_id, params).await
606 }
607
608 pub async fn count_for_owner(
640 client: &RestClient,
641 owner: MetafieldOwner,
642 owner_id: u64,
643 params: Option<MetafieldCountParams>,
644 ) -> Result<u64, ResourceError> {
645 let (parent_id_name, path_template) = match owner {
647 MetafieldOwner::Product => ("product_id", "products/{product_id}/metafields/count"),
648 MetafieldOwner::Variant => ("variant_id", "variants/{variant_id}/metafields/count"),
649 MetafieldOwner::Customer => ("customer_id", "customers/{customer_id}/metafields/count"),
650 MetafieldOwner::Order => ("order_id", "orders/{order_id}/metafields/count"),
651 MetafieldOwner::Collection => (
652 "collection_id",
653 "collections/{collection_id}/metafields/count",
654 ),
655 MetafieldOwner::Page => ("page_id", "pages/{page_id}/metafields/count"),
656 MetafieldOwner::Blog => ("blog_id", "blogs/{blog_id}/metafields/count"),
657 MetafieldOwner::Article => ("article_id", "articles/{article_id}/metafields/count"),
658 MetafieldOwner::Shop => {
659 return Self::count(client, params).await;
661 }
662 };
663
664 let mut ids: HashMap<&str, String> = HashMap::new();
665 ids.insert(parent_id_name, owner_id.to_string());
666
667 let url = build_path(path_template, &ids);
668
669 let query = params
671 .map(|p| serialize_to_query(&p))
672 .transpose()?
673 .filter(|q| !q.is_empty());
674
675 let response = client.get(&url, query).await?;
676
677 if !response.is_ok() {
678 return Err(ResourceError::from_http_response(
679 response.code,
680 &response.body,
681 Self::NAME,
682 None,
683 response.request_id(),
684 ));
685 }
686
687 let count = response
689 .body
690 .get("count")
691 .and_then(serde_json::Value::as_u64)
692 .ok_or_else(|| {
693 ResourceError::Http(crate::clients::HttpError::Response(
694 crate::clients::HttpResponseError {
695 code: response.code,
696 message: "Missing 'count' in response".to_string(),
697 error_reference: response.request_id().map(ToString::to_string),
698 },
699 ))
700 })?;
701
702 Ok(count)
703 }
704}
705
706fn serialize_to_query<T: Serialize>(params: &T) -> Result<HashMap<String, String>, ResourceError> {
708 let value = serde_json::to_value(params).map_err(|e| {
709 ResourceError::Http(crate::clients::HttpError::Response(
710 crate::clients::HttpResponseError {
711 code: 400,
712 message: format!("Failed to serialize params: {e}"),
713 error_reference: None,
714 },
715 ))
716 })?;
717
718 let mut query = HashMap::new();
719
720 if let serde_json::Value::Object(map) = value {
721 for (key, val) in map {
722 match val {
723 serde_json::Value::Null => {}
724 serde_json::Value::String(s) => {
725 query.insert(key, s);
726 }
727 serde_json::Value::Number(n) => {
728 query.insert(key, n.to_string());
729 }
730 serde_json::Value::Bool(b) => {
731 query.insert(key, b.to_string());
732 }
733 serde_json::Value::Array(arr) => {
734 let values: Vec<String> = arr
735 .iter()
736 .filter_map(|v| match v {
737 serde_json::Value::String(s) => Some(s.clone()),
738 serde_json::Value::Number(n) => Some(n.to_string()),
739 _ => None,
740 })
741 .collect();
742 if !values.is_empty() {
743 query.insert(key, values.join(","));
744 }
745 }
746 serde_json::Value::Object(_) => {
747 query.insert(key, val.to_string());
748 }
749 }
750 }
751 }
752
753 Ok(query)
754}
755
756#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
758pub struct MetafieldFindParams {
759 #[serde(skip_serializing_if = "Option::is_none")]
761 pub fields: Option<String>,
762}
763
764#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
766pub struct MetafieldListParams {
767 #[serde(skip_serializing_if = "Option::is_none")]
769 pub namespace: Option<String>,
770
771 #[serde(skip_serializing_if = "Option::is_none")]
773 pub key: Option<String>,
774
775 #[serde(skip_serializing_if = "Option::is_none")]
777 pub metafield_namespaces: Option<String>,
778
779 #[serde(skip_serializing_if = "Option::is_none")]
781 pub limit: Option<u32>,
782
783 #[serde(skip_serializing_if = "Option::is_none")]
785 pub since_id: Option<u64>,
786
787 #[serde(skip_serializing_if = "Option::is_none")]
789 pub fields: Option<String>,
790
791 #[serde(skip_serializing_if = "Option::is_none")]
793 pub page_info: Option<String>,
794
795 #[serde(skip_serializing_if = "Option::is_none")]
797 pub created_at_min: Option<DateTime<Utc>>,
798
799 #[serde(skip_serializing_if = "Option::is_none")]
801 pub created_at_max: Option<DateTime<Utc>>,
802
803 #[serde(skip_serializing_if = "Option::is_none")]
805 pub updated_at_min: Option<DateTime<Utc>>,
806
807 #[serde(skip_serializing_if = "Option::is_none")]
809 pub updated_at_max: Option<DateTime<Utc>>,
810}
811
812#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
814pub struct MetafieldCountParams {
815 #[serde(skip_serializing_if = "Option::is_none")]
817 pub namespace: Option<String>,
818
819 #[serde(skip_serializing_if = "Option::is_none")]
821 pub key: Option<String>,
822}
823
824#[cfg(test)]
825mod tests {
826 use super::*;
827 use crate::rest::{get_path, ResourceOperation};
828
829 #[test]
830 fn test_metafield_struct_serialization() {
831 let metafield = Metafield {
832 id: Some(12345),
833 namespace: Some("custom".to_string()),
834 key: Some("color".to_string()),
835 value: Some("blue".to_string()),
836 metafield_type: Some("single_line_text_field".to_string()),
837 owner_id: Some(67890),
838 owner_resource: Some("product".to_string()),
839 description: Some("Product color".to_string()),
840 created_at: None,
841 updated_at: None,
842 admin_graphql_api_id: Some("gid://shopify/Metafield/12345".to_string()),
843 };
844
845 let json = serde_json::to_string(&metafield).unwrap();
846 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
847
848 assert_eq!(parsed["namespace"], "custom");
850 assert_eq!(parsed["key"], "color");
851 assert_eq!(parsed["value"], "blue");
852 assert_eq!(parsed["type"], "single_line_text_field");
853 assert_eq!(parsed["description"], "Product color");
854
855 assert!(parsed.get("id").is_none());
857 assert!(parsed.get("owner_id").is_none());
858 assert!(parsed.get("owner_resource").is_none());
859 assert!(parsed.get("created_at").is_none());
860 assert!(parsed.get("updated_at").is_none());
861 assert!(parsed.get("admin_graphql_api_id").is_none());
862 }
863
864 #[test]
865 fn test_metafield_deserialization_from_api_response() {
866 let json = r#"{
867 "id": 721389482,
868 "namespace": "inventory",
869 "key": "warehouse",
870 "value": "A-15",
871 "type": "single_line_text_field",
872 "description": "Warehouse location",
873 "owner_id": 632910392,
874 "owner_resource": "product",
875 "created_at": "2024-01-15T10:30:00Z",
876 "updated_at": "2024-06-20T15:45:00Z",
877 "admin_graphql_api_id": "gid://shopify/Metafield/721389482"
878 }"#;
879
880 let metafield: Metafield = serde_json::from_str(json).unwrap();
881
882 assert_eq!(metafield.id, Some(721389482));
883 assert_eq!(metafield.namespace.as_deref(), Some("inventory"));
884 assert_eq!(metafield.key.as_deref(), Some("warehouse"));
885 assert_eq!(metafield.value.as_deref(), Some("A-15"));
886 assert_eq!(
887 metafield.metafield_type.as_deref(),
888 Some("single_line_text_field")
889 );
890 assert_eq!(metafield.description.as_deref(), Some("Warehouse location"));
891 assert_eq!(metafield.owner_id, Some(632910392));
892 assert_eq!(metafield.owner_resource.as_deref(), Some("product"));
893 assert!(metafield.created_at.is_some());
894 assert!(metafield.updated_at.is_some());
895 assert_eq!(
896 metafield.admin_graphql_api_id.as_deref(),
897 Some("gid://shopify/Metafield/721389482")
898 );
899 }
900
901 #[test]
902 fn test_polymorphic_path_selection_with_product_id() {
903 let all_path = get_path(Metafield::PATHS, ResourceOperation::All, &["product_id"]);
905 assert!(all_path.is_some());
906 assert_eq!(
907 all_path.unwrap().template,
908 "products/{product_id}/metafields"
909 );
910
911 let find_path = get_path(
913 Metafield::PATHS,
914 ResourceOperation::Find,
915 &["product_id", "id"],
916 );
917 assert!(find_path.is_some());
918 assert_eq!(
919 find_path.unwrap().template,
920 "products/{product_id}/metafields/{id}"
921 );
922
923 let create_path = get_path(Metafield::PATHS, ResourceOperation::Create, &["product_id"]);
925 assert!(create_path.is_some());
926 assert_eq!(
927 create_path.unwrap().template,
928 "products/{product_id}/metafields"
929 );
930
931 let update_path = get_path(
933 Metafield::PATHS,
934 ResourceOperation::Update,
935 &["product_id", "id"],
936 );
937 assert!(update_path.is_some());
938 assert_eq!(
939 update_path.unwrap().template,
940 "products/{product_id}/metafields/{id}"
941 );
942
943 let delete_path = get_path(
945 Metafield::PATHS,
946 ResourceOperation::Delete,
947 &["product_id", "id"],
948 );
949 assert!(delete_path.is_some());
950 assert_eq!(
951 delete_path.unwrap().template,
952 "products/{product_id}/metafields/{id}"
953 );
954
955 let count_path = get_path(Metafield::PATHS, ResourceOperation::Count, &["product_id"]);
957 assert!(count_path.is_some());
958 assert_eq!(
959 count_path.unwrap().template,
960 "products/{product_id}/metafields/count"
961 );
962 }
963
964 #[test]
965 fn test_polymorphic_path_selection_with_customer_id() {
966 let all_path = get_path(Metafield::PATHS, ResourceOperation::All, &["customer_id"]);
968 assert!(all_path.is_some());
969 assert_eq!(
970 all_path.unwrap().template,
971 "customers/{customer_id}/metafields"
972 );
973
974 let find_path = get_path(
976 Metafield::PATHS,
977 ResourceOperation::Find,
978 &["customer_id", "id"],
979 );
980 assert!(find_path.is_some());
981 assert_eq!(
982 find_path.unwrap().template,
983 "customers/{customer_id}/metafields/{id}"
984 );
985
986 let create_path = get_path(
988 Metafield::PATHS,
989 ResourceOperation::Create,
990 &["customer_id"],
991 );
992 assert!(create_path.is_some());
993 assert_eq!(
994 create_path.unwrap().template,
995 "customers/{customer_id}/metafields"
996 );
997 }
998
999 #[test]
1000 fn test_standalone_path_metafields_id_fallback() {
1001 let find_path = get_path(Metafield::PATHS, ResourceOperation::Find, &["id"]);
1003 assert!(find_path.is_some());
1004 assert_eq!(find_path.unwrap().template, "metafields/{id}");
1005
1006 let update_path = get_path(Metafield::PATHS, ResourceOperation::Update, &["id"]);
1008 assert!(update_path.is_some());
1009 assert_eq!(update_path.unwrap().template, "metafields/{id}");
1010
1011 let delete_path = get_path(Metafield::PATHS, ResourceOperation::Delete, &["id"]);
1013 assert!(delete_path.is_some());
1014 assert_eq!(delete_path.unwrap().template, "metafields/{id}");
1015 }
1016
1017 #[test]
1018 fn test_shop_level_metafield_paths() {
1019 let all_path = get_path(Metafield::PATHS, ResourceOperation::All, &[]);
1021 assert!(all_path.is_some());
1022 assert_eq!(all_path.unwrap().template, "metafields");
1023
1024 let count_path = get_path(Metafield::PATHS, ResourceOperation::Count, &[]);
1026 assert!(count_path.is_some());
1027 assert_eq!(count_path.unwrap().template, "metafields/count");
1028
1029 let create_path = get_path(Metafield::PATHS, ResourceOperation::Create, &[]);
1031 assert!(create_path.is_some());
1032 assert_eq!(create_path.unwrap().template, "metafields");
1033 }
1034
1035 #[test]
1036 fn test_metafield_list_params_serialization() {
1037 let params = MetafieldListParams {
1038 namespace: Some("custom".to_string()),
1039 key: Some("color".to_string()),
1040 metafield_namespaces: Some("custom,inventory".to_string()),
1041 limit: Some(50),
1042 since_id: Some(12345),
1043 fields: Some("id,namespace,key,value".to_string()),
1044 page_info: None,
1045 created_at_min: None,
1046 created_at_max: None,
1047 updated_at_min: None,
1048 updated_at_max: None,
1049 };
1050
1051 let json = serde_json::to_value(¶ms).unwrap();
1052
1053 assert_eq!(json["namespace"], "custom");
1054 assert_eq!(json["key"], "color");
1055 assert_eq!(json["metafield_namespaces"], "custom,inventory");
1056 assert_eq!(json["limit"], 50);
1057 assert_eq!(json["since_id"], 12345);
1058 assert_eq!(json["fields"], "id,namespace,key,value");
1059
1060 let empty_params = MetafieldListParams::default();
1062 let empty_json = serde_json::to_value(&empty_params).unwrap();
1063 assert_eq!(empty_json, serde_json::json!({}));
1064 }
1065
1066 #[test]
1067 fn test_namespace_and_key_filtering() {
1068 let params = MetafieldListParams {
1070 namespace: Some("inventory".to_string()),
1071 key: Some("warehouse".to_string()),
1072 ..Default::default()
1073 };
1074
1075 let json = serde_json::to_value(¶ms).unwrap();
1076 assert_eq!(json["namespace"], "inventory");
1077 assert_eq!(json["key"], "warehouse");
1078 }
1079
1080 #[test]
1081 fn test_value_type_field_serialization_with_rename() {
1082 let metafield = Metafield {
1084 metafield_type: Some("json".to_string()),
1085 ..Default::default()
1086 };
1087
1088 let json = serde_json::to_string(&metafield).unwrap();
1089 assert!(json.contains("\"type\":\"json\""));
1090 assert!(!json.contains("metafield_type"));
1091
1092 let json_input = r#"{"type":"number_integer"}"#;
1094 let parsed: Metafield = serde_json::from_str(json_input).unwrap();
1095 assert_eq!(parsed.metafield_type.as_deref(), Some("number_integer"));
1096 }
1097
1098 #[test]
1099 fn test_all_for_owner_method_signature() {
1100 fn _assert_all_for_owner_signature<F, Fut>(f: F)
1102 where
1103 F: Fn(&RestClient, MetafieldOwner, u64, Option<MetafieldListParams>) -> Fut,
1104 Fut: std::future::Future<
1105 Output = Result<ResourceResponse<Vec<Metafield>>, ResourceError>,
1106 >,
1107 {
1108 let _ = f;
1109 }
1110
1111 }
1114
1115 #[test]
1116 fn test_all_owner_type_paths() {
1117 let variant_all = get_path(Metafield::PATHS, ResourceOperation::All, &["variant_id"]);
1121 assert!(variant_all.is_some());
1122 assert_eq!(
1123 variant_all.unwrap().template,
1124 "variants/{variant_id}/metafields"
1125 );
1126
1127 let order_all = get_path(Metafield::PATHS, ResourceOperation::All, &["order_id"]);
1129 assert!(order_all.is_some());
1130 assert_eq!(order_all.unwrap().template, "orders/{order_id}/metafields");
1131
1132 let collection_all = get_path(Metafield::PATHS, ResourceOperation::All, &["collection_id"]);
1134 assert!(collection_all.is_some());
1135 assert_eq!(
1136 collection_all.unwrap().template,
1137 "collections/{collection_id}/metafields"
1138 );
1139
1140 let page_all = get_path(Metafield::PATHS, ResourceOperation::All, &["page_id"]);
1142 assert!(page_all.is_some());
1143 assert_eq!(page_all.unwrap().template, "pages/{page_id}/metafields");
1144
1145 let blog_all = get_path(Metafield::PATHS, ResourceOperation::All, &["blog_id"]);
1147 assert!(blog_all.is_some());
1148 assert_eq!(blog_all.unwrap().template, "blogs/{blog_id}/metafields");
1149
1150 let article_all = get_path(Metafield::PATHS, ResourceOperation::All, &["article_id"]);
1152 assert!(article_all.is_some());
1153 assert_eq!(
1154 article_all.unwrap().template,
1155 "articles/{article_id}/metafields"
1156 );
1157 }
1158
1159 #[test]
1160 fn test_metafield_get_id_returns_correct_value() {
1161 let metafield_with_id = Metafield {
1162 id: Some(123456789),
1163 namespace: Some("custom".to_string()),
1164 key: Some("test".to_string()),
1165 ..Default::default()
1166 };
1167 assert_eq!(metafield_with_id.get_id(), Some(123456789));
1168
1169 let metafield_without_id = Metafield {
1170 id: None,
1171 namespace: Some("custom".to_string()),
1172 key: Some("new_key".to_string()),
1173 ..Default::default()
1174 };
1175 assert_eq!(metafield_without_id.get_id(), None);
1176 }
1177
1178 #[test]
1179 fn test_metafield_resource_constants() {
1180 assert_eq!(Metafield::NAME, "Metafield");
1181 assert_eq!(Metafield::PLURAL, "metafields");
1182 assert!(Metafield::PATHS.len() > 50); }
1185
1186 #[test]
1187 fn test_metafield_count_params_serialization() {
1188 let params = MetafieldCountParams {
1189 namespace: Some("custom".to_string()),
1190 key: Some("color".to_string()),
1191 };
1192
1193 let json = serde_json::to_value(¶ms).unwrap();
1194 assert_eq!(json["namespace"], "custom");
1195 assert_eq!(json["key"], "color");
1196
1197 let empty_params = MetafieldCountParams::default();
1198 let empty_json = serde_json::to_value(&empty_params).unwrap();
1199 assert_eq!(empty_json, serde_json::json!({}));
1200 }
1201}