Skip to main content

dynamodb_facade/item/
key_id.rs

1/// Zero-sized placeholder used when a key component is a compile-time constant.
2///
3/// `NoId` is the `PkId` or `SkId` type parameter of [`KeyId`] for item types
4/// whose partition key or sort key is a constant (e.g. singleton items like
5/// the `PlatformConfig` in the crate examples). It carries no data because
6/// the key value is baked into the type's
7/// [`HasConstAttribute`](crate::HasConstAttribute) impl.
8///
9/// You will encounter `NoId` as part of [`KeyId::NONE`] for singleton items,
10/// and as the `SkId` of [`KeyId::pk`] for items with a variable PK but a
11/// constant SK.
12///
13/// # Examples
14///
15/// ```
16/// # use dynamodb_facade::test_fixtures::*;
17/// use dynamodb_facade::{KeyId, NoId};
18///
19/// // Singleton item — both PK and SK are constants.
20/// let key_id: KeyId<NoId, NoId> = KeyId::NONE;
21///
22/// // Variable PK, constant SK — SkId is NoId.
23/// let key_id: KeyId<&str, NoId> = KeyId::pk("user-1");
24/// ```
25#[derive(Debug, Clone, Copy, Default)]
26pub struct NoId;
27
28/// Type-safe builder for a DynamoDB partition key + sort key pair.
29///
30/// `KeyId<PkId, SkId>` holds the logical identifiers used to construct a
31/// [`Key<TD>`](crate::Key) for a specific item. The type parameters encode
32/// which key components are present:
33///
34/// | `PkId` | `SkId` | Meaning |
35/// |---|---|---|
36/// | [`NoId`] | [`NoId`] | Both keys are constants — use [`KeyId::NONE`] |
37/// | `T` | [`NoId`] | Variable PK, constant SK — use [`KeyId::pk`] |
38/// | `T` | `U` | Both keys are variable — use [`KeyId::pk`]`.`[`sk`](KeyId::sk) |
39///
40/// The concrete `PkId` and `SkId` types are determined by the item type's
41/// `HasAttribute` impls. For example, a `User` whose PK is derived from a
42/// `&str` user ID has `KeyId<&str, NoId>`.
43///
44/// # Examples
45///
46/// Singleton item (constant PK + SK):
47///
48/// ```
49/// # use dynamodb_facade::test_fixtures::*;
50/// use dynamodb_facade::{DynamoDBItemOp, KeyId};
51///
52/// # async fn example(client: dynamodb_facade::Client) -> dynamodb_facade::Result<()> {
53/// // PlatformConfig has const PK and SK — use KeyId::NONE.
54/// let config = PlatformConfig::get(client, KeyId::NONE).await?;
55/// # Ok(())
56/// # }
57/// ```
58///
59/// Variable PK, constant SK:
60///
61/// ```
62/// # use dynamodb_facade::test_fixtures::*;
63/// use dynamodb_facade::{DynamoDBItemOp, KeyId};
64///
65/// # async fn example(client: dynamodb_facade::Client) -> dynamodb_facade::Result<()> {
66/// // User has a PK and a const SK.
67/// let user = User::get(client, KeyId::pk("user-1")).await?;
68/// # Ok(())
69/// # }
70/// ```
71///
72/// Variable PK + variable SK:
73///
74/// ```
75/// # use dynamodb_facade::test_fixtures::*;
76/// use dynamodb_facade::{DynamoDBItemOp, KeyId};
77///
78/// # async fn example(client: dynamodb_facade::Client) -> dynamodb_facade::Result<()> {
79/// // Enrollment has a PK and a SK.
80/// let user_enrollment = Enrollment::get(client, KeyId::pk("user-1").sk("course-42")).await?;
81/// # Ok(())
82/// # }
83/// ```
84#[derive(Debug, Clone, Copy, Default)]
85pub struct KeyId<PkId, SkId> {
86    /// The partition key identifier.
87    pub(super) pk: PkId,
88    /// The sort key identifier (`NoId` for simple-key tables).
89    pub(super) sk: SkId,
90}
91impl KeyId<NoId, NoId> {
92    /// Shorthand for singleton items whose PK and SK are both compile-time constants.
93    ///
94    /// # Examples
95    ///
96    /// ```
97    /// use dynamodb_facade::{KeyId, NoId};
98    ///
99    /// let key_id: KeyId<NoId, NoId> = KeyId::NONE;
100    /// ```
101    pub const NONE: Self = KeyId { pk: NoId, sk: NoId };
102}
103impl<PkId> KeyId<PkId, NoId> {
104    /// Creates a [`KeyId`] from a partition key ID, leaving the sort key as [`NoId`].
105    ///
106    /// Use this for item types with a variable PK and a constant SK. Chain
107    /// [`sk`](KeyId::sk) afterwards if the sort key is also variable.
108    ///
109    /// # Examples
110    ///
111    /// ```
112    /// use dynamodb_facade::{KeyId, NoId};
113    ///
114    /// let key_id: KeyId<&str, NoId> = KeyId::pk("user-1");
115    /// ```
116    pub fn pk(pk: PkId) -> Self {
117        Self { pk, sk: NoId }
118    }
119
120    /// Adds a sort key ID to produce a composite [`KeyId<PkId, SkId>`].
121    ///
122    /// Use this for item types where both PK and SK are variable.
123    ///
124    /// # Examples
125    ///
126    /// ```
127    /// use dynamodb_facade::KeyId;
128    ///
129    /// let key_id: KeyId<&str, &str>  = KeyId::pk("user-1").sk("course-42");
130    /// ```
131    pub fn sk<SkId>(self, sk: SkId) -> KeyId<PkId, SkId> {
132        KeyId { pk: self.pk, sk }
133    }
134}