dynamodb_facade/schema/mod.rs
1mod attribute_list;
2mod attribute_ref;
3mod attributes;
4mod markers;
5
6pub(crate) use attribute_ref::*;
7pub(crate) use markers::*;
8
9pub use attribute_list::*;
10pub use attributes::*;
11
12mod sealed_traits {
13 /// Seals [`KeySchemaKind`](super::KeySchemaKind) so only `SimpleKey` and `CompositeKey` can implement it.
14 pub trait KeySchemaKindSeal {}
15}
16
17crate::utils::impl_sealed_marker_types!(
18 /// Sealed marker trait for key schema kinds.
19 ///
20 /// Implemented only by [`SimpleKey`] and [`CompositeKey`]. This trait is
21 /// sealed and cannot be implemented outside of this crate. It is used as a
22 /// bound on [`KeySchema::Kind`] to restrict the set of valid key schema
23 /// configurations.
24 KeySchemaKind,
25 sealed_traits::KeySchemaKindSeal;
26 /// Marker type indicating a key schema with a partition key only (no sort key).
27 ///
28 /// Used as the `Kind` associated type on [`KeySchema`] implementations
29 /// generated by [`key_schema!`](crate::key_schema) or
30 /// [`table_definitions!`](crate::table_definitions) when no `SortKey` is
31 /// declared. A table or index with this kind implements
32 /// [`SimpleKeySchema`].
33 ///
34 /// # Examples
35 ///
36 /// ```
37 /// # use dynamodb_facade::test_fixtures::*;
38 /// use dynamodb_facade::{key_schema, KeySchema, SimpleKey};
39 ///
40 /// key_schema! {
41 /// SimpleSchema {
42 /// type PartitionKey = PK;
43 /// }
44 /// }
45 ///
46 /// fn _assert<KS: KeySchema<Kind = SimpleKey>>() {}
47 /// _assert::<SimpleSchema>();
48 /// ```
49 SimpleKey,
50 /// Marker type indicating a key schema with both a partition key and a sort key.
51 ///
52 /// Used as the `Kind` associated type on [`KeySchema`] implementations
53 /// generated by [`key_schema!`](crate::key_schema) or
54 /// [`table_definitions!`](crate::table_definitions) when both `PartitionKey`
55 /// and `SortKey` are declared. A table or index with this kind implements
56 /// [`CompositeKeySchema`].
57 ///
58 /// # Examples
59 ///
60 /// ```
61 /// # use dynamodb_facade::test_fixtures::*;
62 /// use dynamodb_facade::{key_schema, CompositeKey, KeySchema};
63 ///
64 /// key_schema! {
65 /// CompositeSchema {
66 /// type PartitionKey = PK;
67 /// type SortKey = SK;
68 /// }
69 /// }
70 ///
71 /// fn _assert<KS: KeySchema<Kind = CompositeKey>>() {}
72 /// _assert::<CompositeSchema>();
73 /// ```
74 CompositeKey
75);
76
77/// Ensures that a [`KeySchema`] implementation is internally consistent.
78///
79/// Prevents invalid key schema declarations — for example, declaring a
80/// composite key schema without providing a sort key type. This trait is
81/// automatically satisfied for correctly-formed key schemas; you do not
82/// implement or call it directly.
83pub trait ValidKeySchema<KSK: KeySchemaKind> {}
84
85/// Defines the key schema for a DynamoDB table or index.
86///
87/// A key schema specifies the partition key attribute and the key kind
88/// ([`SimpleKey`] or [`CompositeKey`]). Implementations are generated by
89/// [`key_schema!`](crate::key_schema), [`table_definitions!`](crate::table_definitions),
90/// and [`index_definitions!`](crate::index_definitions) — you rarely implement
91/// this trait manually.
92///
93/// For composite key schemas, also implement [`CompositeKeySchema`] to expose
94/// the sort key type. For simple key schemas, also implement [`SimpleKeySchema`].
95///
96/// # Examples
97///
98/// ```
99/// # use dynamodb_facade::test_fixtures::*;
100/// use dynamodb_facade::{KeySchema, TableSchema};
101///
102/// fn _assert<KS: KeySchema>() {}
103/// // PlatformTable's KeySchema associated type implements the KeySchema trait.
104/// _assert::<TableSchema<PlatformTable>>();
105/// ```
106pub trait KeySchema: ValidKeySchema<Self::Kind> {
107 /// Whether this schema has a sort key ([`CompositeKey`]) or not ([`SimpleKey`]).
108 type Kind: KeySchemaKind;
109 /// The partition key attribute definition.
110 type PartitionKey: AttributeDefinition;
111}
112
113/// A [`KeySchema`] with only a partition key (no sort key).
114///
115/// Implemented automatically by [`key_schema!`](crate::key_schema),
116/// [`table_definitions!`](crate::table_definitions) and
117/// [`index_definitions!`](crate::index_definitions) when no `SortKey` is
118/// declared. Tables and indexes with this schema do not expose sort-key
119/// methods on their query builders at compile time.
120///
121/// # Examples
122///
123/// ```
124/// # use dynamodb_facade::test_fixtures::*;
125/// use dynamodb_facade::{IndexSchema, SimpleKeySchema};
126///
127/// fn _assert_simple<KS: SimpleKeySchema>() {}
128/// // TypeIndex has only a PartitionKey.
129/// _assert_simple::<IndexSchema<PlatformTable, TypeIndex>>();
130/// ```
131pub trait SimpleKeySchema: KeySchema<Kind = SimpleKey> {}
132
133/// A [`KeySchema`] with both a partition key and a sort key.
134///
135/// Implemented automatically by [`key_schema!`](crate::key_schema),
136/// [`table_definitions!`](crate::table_definitions) and
137/// [`index_definitions!`](crate::index_definitions) when both `PartitionKey`
138/// and `SortKey` are declared. Tables and indexes with this schema expose
139/// sort-key methods on their query builders (e.g. `sk_eq`, `sk_begins_with`).
140///
141/// # Examples
142///
143/// ```
144/// # use dynamodb_facade::test_fixtures::*;
145/// use dynamodb_facade::{CompositeKeySchema, TableSchema};
146///
147/// fn _assert_composite<KS: CompositeKeySchema>() {}
148/// // PlatformTable's key schema has both PK and SK.
149/// _assert_composite::<TableSchema<PlatformTable>>();
150/// ```
151pub trait CompositeKeySchema: KeySchema<Kind = CompositeKey> {
152 /// The sort key attribute definition.
153 type SortKey: AttributeDefinition;
154}
155impl<KS: KeySchema<Kind = SimpleKey> + SimpleKeySchema> ValidKeySchema<SimpleKey> for KS {}
156impl<KS: KeySchema<Kind = CompositeKey> + CompositeKeySchema> ValidKeySchema<CompositeKey> for KS {}
157
158/// Defines a DynamoDB table: its name and key schema.
159///
160/// Implementations are generated by [`table_definitions!`](crate::table_definitions).
161/// The associated [`KeySchema`] determines whether the table uses a simple or
162/// composite key, and which attribute definitions serve as partition and sort keys.
163///
164/// All items, keys, and operation builders are scoped to a specific table
165/// through this trait, ensuring you cannot accidentally mix items or keys
166/// from different tables.
167///
168/// # Examples
169///
170/// ```
171/// # use dynamodb_facade::test_fixtures::*;
172/// use dynamodb_facade::{table_definitions, TableDefinition};
173///
174/// table_definitions! {
175/// MyTable {
176/// type PartitionKey = PK;
177/// type SortKey = SK;
178/// fn table_name() -> String { "platform".to_owned() }
179/// }
180/// }
181///
182/// fn expect_table<TD: TableDefinition>() {}
183/// expect_table::<MyTable>();
184/// assert_eq!(MyTable::table_name(), "platform");
185/// ```
186pub trait TableDefinition {
187 /// The key schema for this table.
188 type KeySchema: KeySchema;
189 /// Returns the DynamoDB table name.
190 fn table_name() -> String;
191}
192
193/// Convenience alias for the [`KeySchema`] of a [`TableDefinition`].
194///
195/// Use this alias in generic bounds and function signatures to avoid
196/// spelling out the full associated-type projection every time you need
197/// to refer to a table's key schema type.
198///
199/// # Examples
200///
201/// ```
202/// # use dynamodb_facade::test_fixtures::*;
203/// use dynamodb_facade::{CompositeKeySchema, TableDefinition, TableSchema};
204///
205/// // Require that a table's key schema is composite (has both PK and SK).
206/// fn requires_composite_table<TD: TableDefinition>()
207/// where
208/// TableSchema<TD>: CompositeKeySchema,
209/// {}
210///
211/// // PlatformTable has PK + SK, so this compiles.
212/// requires_composite_table::<PlatformTable>();
213/// ```
214pub type TableSchema<TD> = <TD as TableDefinition>::KeySchema;
215
216/// Defines a DynamoDB Global Secondary Index (GSI) or Local Secondary Index (GSI) on
217/// a specific table.
218///
219/// Implementations are generated by [`index_definitions!`](crate::index_definitions).
220/// Each index is associated with a parent table and has its own [`KeySchema`]
221/// describing the index's partition (and optional sort) key.
222///
223/// Index types are used as turbofish parameters on query methods such as
224/// `T::query_index::<MyIndex>(client, key_condition)`.
225///
226/// # Examples
227///
228/// ```
229/// # use dynamodb_facade::test_fixtures::*;
230/// use dynamodb_facade::{index_definitions, IndexDefinition};
231///
232/// index_definitions! {
233/// #[table = PlatformTable]
234/// MyIndex {
235/// type PartitionKey = ItemType;
236/// fn index_name() -> String { "iCustomIndex".to_owned() }
237/// }
238/// }
239///
240/// fn expect_index<TD: IndexDefinition<PlatformTable>>() {}
241/// expect_index::<MyIndex>();
242/// assert_eq!(MyIndex::index_name(), "iCustomIndex");
243/// ```
244pub trait IndexDefinition<TD: TableDefinition> {
245 /// The key schema for this index.
246 type KeySchema: KeySchema;
247 /// Returns the DynamoDB index name.
248 fn index_name() -> String;
249}
250
251/// Convenience alias for the [`KeySchema`] of an [`IndexDefinition`].
252///
253/// Use this alias in generic bounds and function signatures to avoid
254/// spelling out the full associated-type projection every time you need
255/// to refer to an index's key schema type.
256///
257/// # Examples
258///
259/// ```
260/// # use dynamodb_facade::test_fixtures::*;
261/// use dynamodb_facade::{IndexDefinition, IndexSchema, SimpleKeySchema};
262///
263/// // Require that an index's key schema is simple (partition key only).
264/// fn requires_simple_index<I: IndexDefinition<PlatformTable>>()
265/// where
266/// IndexSchema<PlatformTable, I>: SimpleKeySchema,
267/// {}
268///
269/// // TypeIndex has only a partition key, so this compiles.
270/// requires_simple_index::<TypeIndex>();
271/// ```
272pub type IndexSchema<TD, I> = <I as IndexDefinition<TD>>::KeySchema;