1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
//! Primary-key trait surface.
//!
//! Three-trait split per `docs/spec/decisions.md`:
//!
//! - [`PrimaryKey`] (required) — every PK type declares its [`PkType`]
//! discriminant and the schema-emission bits (`SQL_TYPE`, `DEFAULT_SQL`),
//! plus a zero-valued [`sentinel`](PrimaryKey::sentinel) factory used by
//! the macro-emitted `Default` impl.
//! - [`PrimaryKeyDbGen`] (optional) — DB-sourced bulk allocation. Every
//! built-in variant except `Serial` implements it; its deliberate
//! absence on `i32` is load-bearing for `bulk_create` dispatch.
//! - [`PrimaryKeyClientGen`] (optional, custom-only) — client-side single
//! and bulk generation. Built-in PKs never client-generate: HeeRanjId's
//! node/sequence/epoch model requires a database round-trip.
//!
//! Every generation helper takes `&mut DjogiContext`, never a raw pool.
//! The context dispatches to the pool or the active transaction without
//! the caller caring which.
//!
//! # Const-position sentinels via heeranjid 0.3.5+
//!
//! The trait function `<T as PrimaryKey>::sentinel()` is the
//! polymorphic-context entry point. When the caller knows the concrete
//! PK type, **prefer the upstream `T::ZERO` const** (added in heeranjid
//! 0.3.5):
//!
//! ```ignore
//! // Inside #[model(no_default)] constructor helpers:
//! Widget {
//! id: HeerId::ZERO, // const-position OK
//! created_at: DateTime::UNIX_EPOCH,
//! // ...
//! }
//! ```
//!
//! `T::ZERO` is the wire-zero bit pattern, declared `pub const` on each
//! of HeerId / HeerIdDesc / RanjId / RanjIdDesc upstream. The
//! `PrimaryKey::sentinel()` impls in this crate delegate to that const,
//! so the trait fn returns the same wire bytes the const exposes.
//!
//! Use the trait fn when writing code polymorphic over PK type
//! (e.g. inside macro expansions or generic helpers); reach for the
//! const directly otherwise.
//!
//! Heeranjid 0.3.5's `T::ZERO` consts replaced the older
//! `T::new(0, 0, 0)` reconstruction and are now the canonical
//! const-position sentinel values.
//!
//! # Historical note
//!
//! Earlier heeranjid releases did not expose a const sentinel; 0.3.5
//! shipped `T::ZERO`, while `sentinel()` remains the polymorphic entry point.
use crateDjogiContext;
use cratePkType;
use crate;
/// Hidden seal witness type for [`PrimaryKey`].
///
/// `#[doc(hidden)] pub` because the trait associated const
/// `__DJOGI_PK_SEAL` has this type and the trait itself is public —
/// macro emission in downstream crates needs to be able to name the
/// type. The struct has no public constructor; the sole value lives
/// in [`crate::__private::pk_seal::TOKEN`] which routes through the
/// off-limits `__private` namespace. Nothing in the public
/// `djogi::primary_key` path surfaces a constructor — the previous
/// public `__DJOGI_PK_SEAL_TOKEN` re-export is gone.
///
/// Downstream code reaching the value through `djogi::__private` is
/// explicitly violating the framework boundary; same convention as
/// `VisageSealed` in [`crate::__private`].
/// Convert a batch size to the Postgres `INTEGER` parameter used by
/// bulk primary-key allocation helpers. Returns an error when `n`
/// exceeds `i32::MAX` (the database `generate_ids` / `generate_ranjids`
/// functions take an `INTEGER` count).
/// Error used when a bulk primary-key allocation query returns a
/// different number of rows than requested.
/// Contract every primary-key type must satisfy.
///
/// Implementations map the type to its [`PkType`] discriminant, the
/// Postgres column type, the optional `DEFAULT` clause, and the zero
/// value the macro-emitted `Default` impl uses for the `id` field.
///
/// # Sealing
///
/// Sealed via a hidden `PkSealToken` witness — the only paths to a
/// valid impl are the built-in HeerId / RanjId / Serial impls in
/// [`builtins`] and the [`djogi::primary_key!`] macro. Hand-rolled
/// `impl PrimaryKey for …` in downstream crates fail at the
/// [`__DJOGI_PK_SEAL`](Self::__DJOGI_PK_SEAL) const because the token
/// type has no public constructor and the public `djogi::primary_key`
/// path no longer re-exports either the type or its sole instance —
/// macro-emitted code reaches them through
/// [`crate::__private::pk_seal`] (a doc-hidden path under the
/// off-limits `__private` namespace). Matches the
/// [`crate::apps::App`] sealing convention and the `VisageSealed`
/// convention in [`crate::__private`].
/// Optional DB-backed bulk-allocation path.
///
/// Every built-in PK variant except `Serial` implements this. The
/// absence on `i32` is intentional: `bulk_create` for `pk = Serial`
/// models is a compile error today, which
/// matches HeeRanjId's design — client-side bulk allocation requires
/// coordinated node/sequence state that only the database owns.
/// Optional client-side generation path.
///
/// Custom-only. Built-in PKs never client-generate because HeeRanjId's
/// timestamp / node_id / sequence layout requires the database to own
/// the monotonic state. Adopter-defined PK types that can produce an ID
/// locally (UUIDv4, ULID, deterministic hash, etc.) opt in by
/// implementing this trait in addition to [`PrimaryKey`].