json_api/doc/
ident.rs

1use std::cmp::{Eq, PartialEq};
2use std::hash::{Hash, Hasher};
3use std::mem;
4
5use doc::{Data, Document, Object, PrimaryData};
6use error::Error;
7use query::Query;
8use sealed::Sealed;
9use value::{Key, Map, Set, Value};
10use view::Render;
11
12/// Identifies an individual resource. Commonly found in an object's relationships.
13///
14/// Identifiers share their [equality] and [hashing] behavior with [`Object`]. For more
15/// information, check out the *[resource identifier objects]* section of the
16/// JSON API specification.
17///
18/// [`Object`]: ./struct.Object.html
19/// [equality]: ./struct.Object.html#equality
20/// [hashing]: ./struct.Object.html#hashing
21/// [resource identifier objects]: https://goo.gl/vgfzru
22#[derive(Clone, Debug, Deserialize, Serialize)]
23pub struct Identifier {
24    /// A string that contains a unique identfier for this resource type (`kind`). For
25    /// more information, check out the *[identification]* section of the JSON API
26    /// specification.
27    ///
28    /// [identification]: https://goo.gl/3s681i
29    pub id: String,
30
31    /// Describes resources that share common attributes and relationships. This field is
32    /// derived from the `type` field if the identifier is deserialized. For more
33    /// information, check out the *[identification]* section of the JSON API
34    /// specification.
35    ///
36    /// [identification]: https://goo.gl/3s681i
37    #[serde(rename = "type")]
38    pub kind: Key,
39
40    /// Non-standard meta information. If this value of this field is empty, it will not
41    /// be serialized. For more information, check out the *[meta information]* section
42    /// of the JSON API specification.
43    ///
44    /// [meta information]: https://goo.gl/LyrGF8
45    #[serde(default, skip_serializing_if = "Map::is_empty")]
46    pub meta: Map,
47
48    /// Private field for backwards compatibility.
49    #[serde(skip)]
50    _ext: (),
51}
52
53impl Identifier {
54    /// Returns a new `Identifier`.
55    ///
56    /// # Example
57    ///
58    /// ```
59    /// # extern crate json_api;
60    /// #
61    /// # use json_api::Error;
62    /// #
63    /// # fn example() -> Result<(), Error> {
64    /// use json_api::doc::Identifier;
65    /// let mut ident = Identifier::new("users".parse()?, "1".to_owned());
66    /// # Ok(())
67    /// # }
68    /// #
69    /// # fn main() {
70    /// # example().unwrap();
71    /// # }
72    /// ```
73    pub fn new(kind: Key, id: String) -> Self {
74        Identifier {
75            id,
76            kind,
77            meta: Default::default(),
78            _ext: (),
79        }
80    }
81}
82
83impl Eq for Identifier {}
84
85impl From<Object> for Identifier {
86    fn from(object: Object) -> Self {
87        let Object { id, kind, meta, .. } = object;
88        let mut ident = Identifier::new(kind, id);
89
90        ident.meta = meta;
91        ident
92    }
93}
94
95impl<'a> From<&'a Object> for Identifier {
96    fn from(object: &'a Object) -> Self {
97        object.clone().into()
98    }
99}
100
101impl Hash for Identifier {
102    fn hash<H: Hasher>(&self, state: &mut H) {
103        self.id.hash(state);
104        self.kind.hash(state);
105    }
106}
107
108impl PartialEq for Identifier {
109    fn eq(&self, rhs: &Identifier) -> bool {
110        self.id == rhs.id && self.kind == rhs.kind
111    }
112}
113
114impl PartialEq<Object> for Identifier {
115    fn eq(&self, rhs: &Object) -> bool {
116        self.id == rhs.id && self.kind == rhs.kind
117    }
118}
119
120impl Render<Identifier> for Identifier {
121    fn render(mut self, _: Option<&Query>) -> Result<Document<Identifier>, Error> {
122        let meta = mem::replace(&mut self.meta, Default::default());
123
124        Ok(Document::Ok {
125            meta,
126            data: Data::Member(Box::new(Some(self))),
127            included: Default::default(),
128            jsonapi: Default::default(),
129            links: Default::default(),
130        })
131    }
132}
133
134impl Render<Identifier> for Vec<Identifier> {
135    fn render(self, _: Option<&Query>) -> Result<Document<Identifier>, Error> {
136        Ok(Document::Ok {
137            data: Data::Collection(self),
138            included: Default::default(),
139            jsonapi: Default::default(),
140            links: Default::default(),
141            meta: Default::default(),
142        })
143    }
144}
145
146impl PrimaryData for Identifier {
147    fn flatten(self, incl: &Set<Object>) -> Value {
148        incl.into_iter()
149            .find(|item| self == **item)
150            .map(|item| item.clone().flatten(incl))
151            .unwrap_or_else(|| self.id.clone().into())
152    }
153}
154
155impl Sealed for Identifier {}