djogi 0.1.0-alpha.2

Model-first web framework for Rust — web-framework-agnostic core; Axum integration opt-in via the `axum` feature flag
Documentation
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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
//! Djogi — A Model-first web framework for Rust.
//!
//! Define your data schema as Rust structs, and the framework derives
//! everything else: ORM, migrations, admin UI, audit trail, shell bindings,
//! JSONB schema handling.
//!
//! Djogi's core is web-framework-agnostic — it owns the data layer and
//! delegates HTTP routing/middleware/rendering to whichever Rust web
//! framework the adopter chooses. Axum is the most-supported integration
//! target today and ships behind the opt-in `axum` feature flag; it is not
//! a core dependency.
//!
//! # Crate layout at a glance
//!
//! | Module       | Role |
//! |--------------|------|
//! | `config`     | `DjogiConfig` loaded from `Djogi.toml` + env (figment). |
//! | `context`    | `DjogiContext` — carries either a pooled handle or active transaction. Replaces `E: Executor` generics on `Model` + `QuerySet` signatures (Phase 4 Task 1). |
//! | `descriptor` | `ModelDescriptor` and friends — the single source of truth about every registered model. Populated by `#[model]` via `inventory::submit!`. |
//! | `error`      | `DjogiError` — the one error type returned by every `Model` method. |
//! | `model`      | The `Model` trait the macro implements for every user struct. Defined in Phase 1 Task 2. |
//! | `query`      | Filter AST: public API is `Condition` + `FieldRef` (plus `QuerySet<T>` and `OrderExpr`). Low-level enums (`Leaf`, `LookupOp`, `FilterValue`) live under `djogi::query::internal` for advanced/custom emitters. Filled in across Phase 2. |
//! | `relation`   | Relation field types — `ForeignKey<T>`, `OneToOneField<T>`, resolved-cache wrappers, and `OnDelete`. Landed in Phase 3 Task 1; extended by Tasks 2–6 with `RelationPath`, `ManyToMany`, and the macro glue. |
//! | `types`      | `DateTime`, `Date`, and re-exports of `HeerId`/`RanjId` — the canonical types imported via `prelude`. |
//!
//! # Recommended usage
//!
//! ```ignore
//! use djogi::prelude::*;
//!
//! #[model(table = "posts")]
//! struct Post {
//!     title: String,
//!     body: String,
//! }
//! ```
//!
//! `prelude::*` brings in the `#[model]` attribute macro, `Model` trait,
//! canonical types (`DateTime`, `Date`, `HeerId`, `RanjId`), and the
//! `DjogiError` enum — everything a model definition needs.

// Alias the current crate as `djogi` under test so the absolute
// `::djogi::*` paths emitted by `#[djogi_test]` (and any other macro that
// hard-codes the crate name) resolve when used from inside this crate's
// own unit-test modules. Outside of tests, the dependency graph already
// carries the name; under `cargo test --lib` the crate root has no
// `djogi` entry without this self-extern.
#[cfg(test)]
extern crate self as djogi;

#[doc(hidden)]
pub mod __bypass;
pub mod apps;
pub mod array;
pub mod auth;
pub mod cache;
pub mod compose;
pub mod config;
pub mod context;
pub mod descriptor;
pub mod enum_;
pub mod error;
pub mod expr;
pub mod field_codec;
pub mod fts;
pub mod fts_query;
#[cfg(feature = "spatial")]
pub mod geo;
pub mod hooks;
pub(crate) mod ident;
pub mod intent;
pub mod jsonb;
pub mod live_migrate;
pub mod migrate;
pub mod model;
#[cfg(feature = "notify")]
pub mod notify;
pub mod outbox;
pub mod pg;
// Phase 8.5 Cluster 4 (djogi#170 umbrella) — typed Postgres newtypes
// with hand-rolled wire codecs. Ships `Interval` (djogi#212), `Range<T>`
// (djogi#215 substrate), and the network family (`MacAddr` /
// `CidrAddr`, djogi#213, behind the `network` feature flag). Future
// umbrella dispatches add more newtypes alongside without reshaping
// the public surface.
pub mod pg_types;
pub mod presentation;
pub mod primary_key;
pub mod query;
pub mod range;
pub mod relation;
pub mod snapshot;
pub mod testing;
pub mod tracked;
pub mod trait_registry;
pub mod transaction;
pub mod types;
pub mod visage;
pub mod visage_boundary;

// T7 fixup — re-export `DjogiVisageOf` at crate root so adopter code that
// bounds generics on "something that projects model M" can spell the
// trait as `djogi::DjogiVisageOf<M>` rather than reaching into the
// internal `visage_boundary` module. The trait itself is stable public
// API; only the module it lives in is implementation-detail.
pub use visage_boundary::DjogiVisageOf;

// Cluster 8δ T7.4 — `SassiBootHook` re-export so `#[derive(Model)]`-emitted
// `inventory::submit!` blocks can spell `::djogi::SassiBootHook` per
// `feedback_macro_path_routing.md` (macro paths route through djogi only).
//
// GH #125 — re-exported under `#[doc(hidden)]` to keep this link-time
// machinery off the v0.1.0 adopter-facing surface. The type itself is
// already `#[doc(hidden)]` at its definition site (`cache::boot`); the
// re-export carries the same marker so `cargo doc` does not surface
// the path under the crate root either.
#[doc(hidden)]
pub use crate::cache::SassiBootHook;

/// Private re-exports used only by macro-generated code.
///
/// These are `#[doc(hidden)]` because they are an implementation detail of the
/// `#[model]` macro, not part of the public API. Macro-emitted code uses fully
/// qualified paths like `::djogi::__private::inventory::submit!` so that users
/// only need `djogi` as a direct dependency — they never need to add
/// `inventory` or `time` themselves.
///
/// T2 adds `::djogi::__private::pg` containing the new SQL substrate types
/// (`SqlAccumulator`, `PgConnection`, `ToSql`, `FromSql`, `PgRow`). Macro-
/// emitted code routes through `::djogi::__private::pg::*` rather than
/// importing `tokio_postgres` / `postgres_types` directly.
#[doc(hidden)]
pub mod __private {
    pub use futures;
    pub use inventory;
    pub use postgres_types;
    /// `rust_decimal` re-export for macro-emitted `u64 → Decimal` bind shims.
    ///
    /// Macro-emitted code routes `Decimal` through
    /// `::djogi::__private::rust_decimal::Decimal` so adopter crates do not
    /// need a direct `rust_decimal` dependency — only `djogi` needs it.
    /// Per `feedback_macro_path_routing.md`: macro paths route through
    /// `::djogi::*` only; the macro never names upstream crates directly.
    pub use rust_decimal;
    pub use serde;
    pub use tokio;
    pub use tokio_postgres;

    /// New SQL substrate re-exports for macro-emitted code.
    ///
    /// Macro emission routes through `::djogi::__private::pg::*` rather than
    /// directly importing `tokio_postgres::*` or `postgres_types::*` — this
    /// keeps the macro output decoupled from the exact crate versions and
    /// allows Djogi to add wrapper types without changing the macro-emitted
    /// call sites. See `feedback_macro_path_routing.md` for the rationale.
    pub use bytes;

    pub mod pg {
        pub use crate::pg::accumulator::SqlAccumulator;
        pub use crate::pg::connection::PgConnection;
        /// Canonical row-decode trait (T3). Emitted by `#[model]` with
        /// `const COLUMNS`, `const COLUMN_LIST`, and an ordinal
        /// `from_pg_row` body guarded by per-column `debug_assert!`s.
        pub use crate::pg::decode::{
            FromJoinedPgRow, FromPgRow, decode_at, decode_derived_at, decode_narrowed,
            decode_narrowed_by_name, decode_narrowed_opt, decode_narrowed_opt_by_name,
            decode_opt_u64_from_decimal, decode_opt_u64_from_decimal_by_name,
            decode_u64_from_decimal, decode_u64_from_decimal_by_name, joined_alias_for_prefix,
            try_get_scalar,
        };
        pub use ::postgres_types::{FromSql, ToSql, Type as PgType};
        pub use ::tokio_postgres::Row as PgRow;
        pub use ::tokio_postgres::Statement;
    }

    /// Reflexive type-equality witness. Implemented for every `T` as
    /// `T: SameAs<T>`, so the **only** way for `A: SameAs<B>` to hold is
    /// `A == B`. Used by `{Model}Filter` setters to pin a method's value
    /// generic to the column's declared Rust type while keeping the
    /// `IntoFilterValue` bound deferrable (see the setter emission in
    /// `djogi-macros/src/model/filter.rs`). Not intended for downstream
    /// use — this lives in `__private` and carries no stability
    /// guarantee.
    pub trait SameAs<T: ?Sized> {}
    impl<T: ?Sized> SameAs<T> for T {}

    /// Visage boundary marker + its seal.
    ///
    /// Proc-macro-emitted visages impl `Sealed<M>` and `DjogiVisageOf<M>`
    /// for their source model `M`. Downstream code cannot satisfy the
    /// sealed supertrait, so no hostile `impl DjogiVisageOf<OtherModel>`
    /// can slip in. The re-export through `__private` keeps the macro
    /// output routed through `::djogi::*` paths per
    /// `feedback_macro_path_routing.md`.
    pub use crate::visage_boundary::DjogiVisageOf;
    pub use crate::visage_boundary::private::Sealed as VisageSealed;

    /// Closed-world metadata seal for [`crate::DjogiVisage`] — Phase 8.5
    /// issue #231 reconciliation.
    ///
    /// Distinct from `VisageSealed`: `VisageSealed<M>` carries a
    /// reflexive `impl<M: Model> VisageSealed<M> for M` blanket so
    /// `DjogiVisageOf<M>` accepts the model itself as a "degenerate
    /// visage". That blanket made `DjogiVisageOf<Self::Model>` alone
    /// **not** a closed-world gate on `DjogiVisage` — any
    /// `MyModel: Model` could satisfy `DjogiVisageOf<MyModel>`
    /// reflexively, allowing a hand-rolled
    /// `impl DjogiVisage for MyModel { type Model = Self; ... }` to
    /// fabricate a visage that never went through the `#[model]`
    /// macro's emission path.
    ///
    /// `DjogiVisageSealed` plugs that gap: **no reflexive blanket**.
    /// The single emitter is the `#[model]` proc macro, which
    /// emits `impl ::djogi::__private::DjogiVisageSealed for {Visage}`
    /// alongside the `DjogiVisage` trait impl. Hand-implementing
    /// `DjogiVisageSealed` from downstream code is outside the
    /// public contract — the `__private` re-export is the
    /// convention-only seam (same boundary as `VisageSealed`,
    /// `apps_seal`, `pk_seal`, and `hooks::__seal::Sealed`); we
    /// reserve the right to break that code in any future release
    /// without notice.
    pub use crate::visage::private::Sealed as DjogiVisageSealed;

    /// Seal for macro-emitted [`DerivedParity`](crate::testing::DerivedParity)
    /// trait impls — Phase 8.5 issue #231 reconciliation. Adopters do
    /// not impl `DerivedParity` themselves; the bound is satisfied
    /// only by `#[model]`-emitted visages with at least one in-scope
    /// derived entry. Re-exported through `__private` so the macro
    /// emission path can satisfy the supertrait without naming
    /// `crate::testing::private::DerivedParitySealed` directly (which
    /// would route adopter `use djogi::testing::private::*` calls
    /// through a `#[doc(hidden)]` module).
    pub use crate::testing::private::DerivedParitySealed;

    /// Sealed projection-entry discriminant for the
    /// [`DjogiVisage::PROJECTIONS`](crate::DjogiVisage::PROJECTIONS)
    /// trait constant. Re-exported here so macro-emitted code routes
    /// through `::djogi::__private::ProjectionEntry` per
    /// `feedback_macro_path_routing.md` — adopter code never names this
    /// type. Phase 8.5 issue #231. See the module-level docs on
    /// [`crate::visage::projection`] for the convention seal.
    pub use crate::visage::projection::ProjectionEntry;

    /// Hidden seal-token witnesses for [`crate::primary_key::PrimaryKey`]
    /// and [`crate::apps::App`].
    ///
    /// The public `djogi::primary_key` and `djogi::apps` paths used to
    /// re-export the token consts (`__DJOGI_PK_SEAL_TOKEN`,
    /// `__DJOGI_APPS_SEAL_TOKEN`). That made the seals bypassable —
    /// downstream code could grab the public consts and hand-roll a
    /// trait impl. The consts now live only here, under the
    /// `__private` namespace whose contract states "downstream code
    /// reaching in is breaking the framework boundary; we reserve the
    /// right to break that code in any future release without notice."
    /// Same convention as `VisageSealed` above.
    pub mod pk_seal {
        pub use crate::primary_key::PkSealToken;

        /// Sole [`PkSealToken`] value — reached from macro-emitted
        /// code via `::djogi::__private::pk_seal::TOKEN`.
        pub const TOKEN: PkSealToken = PkSealToken::__new();
    }
    pub mod apps_seal {
        pub use crate::apps::SealToken;

        /// Sole [`SealToken`] value — reached from macro-emitted code
        /// via `::djogi::__private::apps_seal::TOKEN`.
        pub const TOKEN: SealToken = SealToken::__new();
    }

    /// Hook-dispatch re-exports for the `#[model(hooks)]` macro (T1.3).
    ///
    /// The macro-emitted code routes through `::djogi::__private::hooks::*`
    /// rather than `::djogi::hooks::*` so the seal supertrait
    /// (`Sealed`, otherwise unnameable from outside the `djogi` crate)
    /// is reachable in the macro's emission context. Adopter code uses
    /// the public surface — `djogi::ModelHooks` for the trait one
    /// implements, `djogi::hooks::HasHooks` for trait bounds — and never
    /// touches this module.
    ///
    /// Per `feedback_macro_path_routing.md`: macro-emitted paths route
    /// through `::djogi::*` only; the macro never reaches into
    /// `::heeranjid::*` / `::time::*` / `::uuid::*` / etc. directly.
    pub mod hooks {
        pub use crate::hooks::__seal::{MarkerSeal, Sealed};
        pub use crate::hooks::HasHooks;
        pub use crate::hooks::ModelHooks;
    }

    /// `tracing` re-export for macro-generated `_insecurely()` warn! calls.
    ///
    /// Routing through `::djogi::__private::tracing` keeps user crates from
    /// needing `tracing` as a direct dependency — the same path-routing
    /// convention used for `inventory`, `postgres_types`, and `futures`.
    pub use tracing;

    /// Q-algebra seal extension — routed through `__private` so the
    /// proc-macro's emitted `IntoQ<#model>` impl for `{Model}Filter`
    /// can satisfy the crate-private `sealed_into_q::Sealed`
    /// supertrait from inside the adopter crate.
    ///
    /// Adopter code never names this trait — `IntoQ<T>` is the public
    /// surface. Only `djogi-macros::model::filter` reaches in here,
    /// and only to stamp the seal on the `{Model}Filter` types it
    /// generates.
    ///
    /// See `crate::query::q::__SealedIntoQ` for the underlying
    /// crate-private seal, and `query::q::IntoQ` for the public
    /// trait downstream code consumes.
    pub use crate::query::q::__SealedIntoQ;

    /// Re-exports needed by the `IntoQ<#model>` impl macro emission
    /// in `djogi-macros::model::filter`. Adopter code uses
    /// `crate::query::filter::clauses_into_condition` ↔ `Q::Condition(_)`
    /// indirectly via `filter_struct(my_filter)`; the helper exists at
    /// this path so macro-emitted code can route through
    /// `::djogi::__private::query::*` per `feedback_macro_path_routing.md`.
    ///
    /// Phase 8eta PR2a additions (consumed by PR2b's direct-`Q<T>` SQL
    /// walker and PR2d's macro override):
    ///
    /// - `SqlEmitContext` — the parent-table-threading context PR2d's
    ///   generated `__djogi_emit_field_predicate` arms expect.
    /// - `PortablePredicateError` — the typed lowering error PR2b's
    ///   walker propagates back to `DjogiError`.
    /// - `__make_djogi_field` — the macro constructor PR3 will route every
    ///   generated `{Model}Fields` accessor through.
    pub mod query {
        pub use crate::query::condition::{FilterValue, LookupOp};
        pub use crate::query::field::djogi_field_macro_support::__make_djogi_field;
        pub use crate::query::filter::{FilterClauseParts, clauses_into_condition, clauses_into_q};
        pub use crate::query::portable::{PortablePredicateError, SqlEmitContext};
        pub use crate::query::q::{IntoQ, Q};

        // Phase 8eta PR2b — hidden re-export of the portable SQL helper
        // module. PR2d's macro-emitted
        // `Model::__djogi_emit_field_predicate` override consumes
        // `::djogi::__private::query::portable_emit::*`. The helpers
        // themselves live at `crate::query::portable::emit::*` (a
        // hidden public submodule); the re-export here keeps macro
        // path-routing through `::djogi::*` per
        // `feedback_macro_path_routing.md`.
        pub use crate::query::portable::emit as portable_emit;
    }
}

pub use apps::{App, AppDescriptor, AppIdentity, AppRegistry, CrossAppEdge};
// `AppDiagnostic` is reserved for future migration consumers (compose / status
// / attune) per its module doc — currently not wired in production. Keep
// the symbol available cross-crate but hide it from rustdoc until a real
// consumer lands and the variant set stabilises.
#[doc(hidden)]
pub use apps::AppDiagnostic;
// Phase 8 §T2.1 — composition primitives. The runtime trait surfaces.
// `Auditable` impls are emitted by `#[model(auditable)]` (T2.4 — the
// surface superseded T2.2's `#[derive(Auditable)]` per spec line 1037,
// locked 2026-05-03); `SoftDeletable` impls are emitted by
// `#[model(soft_deletable)]` (T2.6 — the surface superseded T2.3's
// `#[derive(SoftDeletable)]` for the same proc-macros-cannot-observe-
// sibling-derives constraint).
pub use compose::{Auditable, SoftDeletable};
pub use context::DjogiContext;
pub use descriptor::{
    ComputedFieldDescriptor, DefaultVolatility, DeferrabilitySpec, DerivedProjection,
    EnumDescriptor, FieldDescriptor, FieldSqlType, GeographySubtype, IndexColumnSpec, IndexKind,
    IndexNameKind, IndexNameTarget, IndexNullsOrder, IndexOrder, IndexSpec, IndexTarget, IndexType,
    ModelDescriptor, PartitionSpec, PkType, ProtectedFieldMetadata, RangeSubtypeKind,
    RedactionPolicy, RetentionLabel, RustSourceType, Sensitivity, VisageDescriptor, index_name,
};
pub use pg::pool::DjogiPool;
// Top-level `djogi::GeoPoint` re-export for spatial models. Feature-gated so
// the symbol does not appear in default-feature builds or `cargo doc` output
// when PostGIS support is not requested.
pub use djogi_macros::{
    DjogiEnum, JsonbSchema, Model, apps, deliberately_bypass_convention_with_raw_sql, many_to_many,
    primary_key, reverse_one_to_many, reverse_one_to_one, trait_impl,
};
#[cfg(feature = "spatial")]
pub use geo::GeoPoint;
pub use hooks::ModelHooks;
pub use jsonb::{
    Jsonb, JsonbPathRef, JsonbSchema, JsonbSqlCast, MirJzSON, MirJzSONError, UnknownField,
    UnknownFieldExt,
};
// `FromPgRow` is the canonical row-decode trait — adopters write
// `ctx.raw_query::<MyType>(...)` against it, so it stays in the public
// rustdoc surface. The other four below are macro-emission targets and
// raw helpers that adopter code does not implement directly: macros emit
// `impl ::djogi::pg::decode::FromJoinedPgRow for T`; `try_get_scalar` is
// used by the `djogi::primary_key!` macro for newtype-PK decode.
// `FromRowTuple` + `try_get_tuple` are module-internal today (the public
// `raw_query` bound is `FromPgRow`, not `FromRowTuple`). Hide them from
// rustdoc; keep the symbols available for macro emission and any future
// raw-tuple-decode promotion.
pub use pg::decode::FromPgRow;
#[doc(hidden)]
pub use pg::decode::{FromJoinedPgRow, try_get_scalar};
pub use primary_key::{PrimaryKey, PrimaryKeyClientGen, PrimaryKeyDbGen};
// The `#[djogi_test]` attribute macro re-exported for convenience. The macro
// itself is always available (proc macros have no runtime component); the
// *runtime helper* it calls (`::djogi::testing::setup_test_db`) is gated on
// `cfg(any(test, feature = "testing"))` so the generated code only compiles
// in test or feature-enabled builds.
pub use djogi_macros::djogi_test;
pub use error::{DbError, DjogiError};

/// Crate-scoped `Result` alias — `Result<T, DjogiError>`.
///
/// Every fallible Djogi operation returns a `DjogiError` from a single
/// public error type, so adopter code can name the success type alone:
///
/// ```ignore
/// use djogi::prelude::*;
///
/// async fn publish(ctx: &mut DjogiContext, id: HeerId) -> djogi::Result<Article> {
///     let mut article = Article::get(ctx, id).await?;
///     article.published = true;
///     article.save(ctx).await?;
///     Ok(article)
/// }
/// ```
///
/// The alias mirrors the convention exported by `tokio::io::Result`,
/// `sqlx::Result`, and most other Rust libraries that own a single error
/// type — adopters expect `djogi::Result<T>` to exist and can write it
/// without naming `DjogiError` directly. Prefer this alias at API
/// boundaries; reach for the explicit `Result<T, DjogiError>` form only
/// when a function returns a non-Djogi error (in which case it should
/// not be using this alias anyway).
///
/// Intentionally **not** re-exported through `djogi::prelude` — including
/// it would shadow `std::result::Result<T, E>` at every adopter call site
/// that wrote `Result<T, E>` for a non-djogi error. Spell it
/// `djogi::Result<T>` at function signatures (same shape as
/// `tokio::io::Result`, `sqlx::Result`).
pub type Result<T> = std::result::Result<T, DjogiError>;

pub use expr::{
    AggregateExpr, Case, CaseBuilder, DenseRank, Exists, Expr, HypotheticalSetAgg, KindEvidence,
    MetadataAgg, OrderedSetAgg, OuterRef, QualifyCondition, QualifyOp, Rank, RowNumber, Subquery,
    ValueAgg, WindowRanking, grouping_of,
};
#[cfg(feature = "spatial")]
pub use expr::{BinaryRowAgg, MvtOptions, RowAggregate, RowKindEvidence};
// Field-level codec public surface. `FieldCodec` is the trait adopters
// implement for at-rest column transformations.
pub use field_codec::FieldCodec;
// `is_codec_registered` is consumed by the macro layer to validate
// `#[field(codec = "…")]` strings at expansion time. Adopter code does
// not call it directly. Hide from rustdoc; keep the symbol available
// cross-crate for macro emission.
#[doc(hidden)]
pub use field_codec::is_registered as is_codec_registered;
pub use fts::{FtsDescriptor, TsQuery, TsVector};
pub use fts_query::FtsFieldRef;
// Cluster 8γ Stage 2 (T6.9b): `Condition` retired from the crate
// root re-export. The public predicate substrate is `Q<T>`; the
// legacy `Condition` type lives at `djogi::query::internal::Condition`
// for the few cross-cluster consumers that still name it (8β's
// `default_filter_condition` trait method, integration tests
// asserting on tree shape). Adopter code composes through `Q<T>` and
// never reaches for `Condition` directly.
pub use query::{
    AggregateQuery, AnnotatedQuerySet, ArrayPredicate, BasicPredicate, CachedPortableQuerySet,
    ClosureModel, ConditionExt, DjogiPortableEq, FieldRef, FilterClause, InnerLateral,
    InsertSelectColumn, InsertSelectSource, InsertSelectStmt, IntoAggregateTuple,
    IntoFieldFilterValue, IntoFilterValue, IntoInsertColumns, IntoPortableFieldValue, IntoSetOpArm,
    JoinedAnnotatedQuerySet, JoinedAnnotatedRow, JoinedQuerySet, LateralQuerySet, LeftLateral,
    Lookup, MaterializeClosureOptions, MaterializeClosureReport, MergeCounts, MergeStmt,
    ModelCursorStream, ModelFilter, OrderExpr, PairClosureKinshipSum, PairOrderExpr, PairSide,
    PairWindowExt, PortableQuerySet, Q, QuerySet, RawCursorStream, RecursiveDirection,
    RecursiveQuerySet, SetOpKind, SetOpQuerySet, UpdateAssignment, UpdateStmt, VisageQuerySet,
};
pub use relation::{
    ForeignKey, ForeignKeyResolved, JoinedRow, ManyToMany, OnDelete, OneToOneField,
    OneToOneFieldResolved, PrefetchedRow,
};
pub use tracked::Tracked;
pub use types::{
    Date, DateTime, HeerId, HeerIdDesc, HeerIdRecencyBiased, Interval, Range, RangeBound, RanjId,
    RanjIdDesc, RanjIdRecencyBiased,
};
// djogi#213 — typed Postgres network types (`network` feature).
#[cfg(feature = "network")]
pub use types::{CidrAddr, CidrAddrError, MacAddr, MacAddrParseError};
pub use visage::{DjogiVisage, VisageError};

/// The canonical adopter import.
///
/// `use djogi::prelude::*;` brings the framework's adopter-facing surface into
/// scope in a single line: every type a model definition or CRUD call site
/// needs, every macro the model surface depends on, and the canonical type
/// re-exports (`HeerId`, `RanjId`, `Date`, `DateTime`).
///
/// # Example
///
/// ```ignore
/// use djogi::prelude::*;
///
/// #[model(table = "articles")]
/// pub struct Article {
///     pub title: String,
///     pub body: String,
///     pub published: bool,
/// }
///
/// async fn publish(ctx: &mut DjogiContext, id: HeerId) -> djogi::Result<Article> {
///     let mut article = Article::get(ctx, id).await?;
///     article.published = true;
///     article.save(ctx).await?;
///     Ok(article)
/// }
/// ```
///
/// # What is in scope
///
/// - **Framework macros** — `#[model]`, `#[djogi_test]`, `apps!`, `primary_key!`,
///   `#[derive(DjogiEnum)]`, `#[derive(JsonbSchema)]`, plus the serde derives so
///   adopter-side typed JSONB schemas can `#[derive(Serialize, Deserialize)]`
///   without an explicit `serde` import line.
/// - **Core data types** — `Model`, `DjogiContext`, `DjogiError`,
///   `QuerySet`, `Q<T>`, `FieldRef`, `FilterClause`, `Lookup`, `OrderExpr`,
///   `ForeignKey<T>`, `OneToOneField<T>`, `ManyToMany<T>`, `Jsonb<T>`,
///   `Tracked<T>`, the canonical PK newtypes (`HeerId`, `HeerIdDesc`,
///   `RanjId`, `RanjIdDesc`), and `time` types (`Date`, `DateTime`).
/// - **Composition primitives** — `Auditable`, `SoftDeletable` (the runtime
///   trait surfaces; `#[model(auditable)]` / `#[model(soft_deletable)]` emit
///   the impls).
/// - **Transaction helpers** — `atomic` (the canonical scope helper),
///   `atomic_with` (sibling that opens at an explicit Postgres
///   isolation level), `retry_on_conflict` (the immediate lock-conflict /
///   serialization-failure retry loop), `retry_on_conflict_with_backoff`
///   and `TransactionRetryBackoff` (production retry policy for
///   contention / `PoolTimeout`), `IsolationLevel` (`READ COMMITTED` /
///   `REPEATABLE READ` / `SERIALIZABLE` typed surface for `atomic_with`),
///   and `DeferScope` (the typed scope for
///   `DjogiContext::defer_constraints` / `set_constraints_immediate`).
/// - **Spatial primitive** — `GeoPoint` is included when the `spatial`
///   feature is enabled; otherwise it is absent from the prelude.
///
/// # What is *not* in scope
///
/// - **The crate-scoped `Result<T>` alias.** Adopters spell it
///   `djogi::Result<T>` at function signatures (the same shape used by
///   `tokio::io::Result`, `sqlx::Result`, etc.). Pulling it through the
///   prelude would shadow `std::result::Result<T, E>` at every adopter
///   call site that uses the two-argument form for a non-djogi error.
/// - **The raw SQL escape hatches.** `RawAccessExt` / `RawPoolAccessExt`
///   live on the sealed `djogi::__bypass` module and are reachable only
///   through the `#[djogi::deliberately_bypass_convention_with_raw_sql]`
///   attribute — pulling them through the prelude would lose the
///   "escape hatch is djogi's `unsafe`" framing. See
///   [`docs/spec/raw-sql-escape-hatches.md`](https://github.com/tarunvir/djogi/blob/main/docs/spec/raw-sql-escape-hatches.md).
/// - **Migration substrate.** Items under `djogi::migrate::*` are reached
///   explicitly when an adopter wraps the migration runner from app code;
///   the CLI is the canonical surface for routine use.
/// - **The `__private` macro-emission re-exports.** Macro-emitted code
///   routes through `::djogi::__private::*` per the path-routing
///   convention; adopter code never names those paths.
///
/// The prelude is the framework's stability commitment for adopter imports —
/// names land here once they are intended to live for the long haul.
pub mod prelude {
    #[doc(hidden)]
    pub use crate::apps::AppDiagnostic;
    pub use crate::apps::{App, AppDescriptor, AppIdentity, AppRegistry, CrossAppEdge};
    // Phase 8 §T2.1 — composition primitives (see crate root re-export).
    pub use crate::compose::{Auditable, SoftDeletable};
    pub use crate::context::DjogiContext;
    pub use crate::descriptor::{
        DefaultVolatility, DeferrabilitySpec, EnumDescriptor, FieldDescriptor, FieldSqlType,
        GeographySubtype, IndexColumnSpec, IndexKind, IndexNullsOrder, IndexOrder, IndexSpec,
        IndexTarget, IndexType, ModelDescriptor, PartitionSpec, PkType, ProtectedFieldMetadata,
        RangeSubtypeKind, RedactionPolicy, RetentionLabel, RustSourceType, Sensitivity,
    };
    pub use crate::error::{DbError, DjogiError};
    // The `djogi::Result<T>` alias is intentionally NOT re-exported through
    // the prelude. Including it would shadow `std::result::Result<T, E>` at
    // every adopter call site that wrote `Result<T, E>` for a non-djogi
    // error, breaking type-resolution for the two-argument form. Adopters
    // who want the alias spell it `djogi::Result<T>` at function signatures
    // — the same shape `tokio::io::Result` / `sqlx::Result` use today.
    pub use crate::expr::{
        AggregateExpr, Case, CaseBuilder, DenseRank, Exists, Expr, HypotheticalSetAgg,
        KindEvidence, MetadataAgg, OrderedSetAgg, OuterRef, QualifyCondition, QualifyOp, Rank,
        RowNumber, Subquery, ValueAgg, WindowRanking, grouping_of,
    };
    #[cfg(feature = "spatial")]
    pub use crate::expr::{BinaryRowAgg, MvtOptions, RowAggregate, RowKindEvidence};
    // `FieldCodec` is the trait adopters implement when declaring a
    // codec — belongs in the prelude because protected-field
    // declarations live in adopter model files. `is_codec_registered`
    // is the lookup the macro layer uses to validate
    // `#[field(protected(codec = "<id>"))]` at expansion time;
    // adopter code does not call it directly.
    pub use crate::field_codec::FieldCodec;
    #[doc(hidden)]
    pub use crate::field_codec::is_registered as is_codec_registered;
    pub use crate::fts::{FtsDescriptor, TsQuery, TsVector};
    pub use crate::fts_query::FtsFieldRef;
    pub use crate::hooks::ModelHooks;
    pub use crate::jsonb::{
        Jsonb, JsonbPathRef, JsonbSchema, JsonbSqlCast, MirJzSON, MirJzSONError, UnknownField,
        UnknownFieldExt,
    };
    pub use crate::model::Model;
    // DjogiPool is the adopter-facing pool handle. It belongs in the prelude
    // because pool construction (`DjogiPool::connect`, `DjogiPoolBuilder`) is
    // the framework entry point — adopters spell it without a full path.
    pub use crate::pg::decode::FromPgRow;
    #[doc(hidden)]
    pub use crate::pg::decode::{FromJoinedPgRow, try_get_scalar};
    pub use crate::pg::pool::DjogiPool;
    // Cluster 8γ Stage 2 (T6.9b): `Condition` retired from the
    // prelude. Adopter code composes through `Q<T>` (in this list);
    // legacy `Condition` callers reach `djogi::query::internal::Condition`.
    pub use crate::query::{
        AggregateQuery,
        AnnotatedQuerySet,
        ArrayPredicate,
        BasicPredicate,
        CachedPortableQuerySet,
        ClosureModel,
        ConditionExt,
        // Phase 8.5 djogi#103 + GH#299 — VALUES join (inner, left, cross).
        CrossValuesJoinedQuerySet,
        DjogiPortableEq,
        FieldRef,
        FilterClause,
        InlineValues,
        InsertSelectColumn,
        InsertSelectSource,
        InsertSelectStmt,
        IntoAggregateTuple,
        IntoFieldFilterValue,
        IntoFilterValue,
        IntoInsertColumns,
        IntoPortableFieldValue,
        IntoSetOpArm,
        IntoValuesColumns,
        JoinedAnnotatedQuerySet,
        JoinedAnnotatedRow,
        JoinedQuerySet,
        LeftValuesJoinedQuerySet,
        Lookup,
        MaterializeClosureOptions,
        MaterializeClosureReport,
        MergeCounts,
        MergeStmt,
        ModelFilter,
        OrderExpr,
        PairClosureKinshipSum,
        PairOrderExpr,
        PairSide,
        PairWindowExt,
        PortableQuerySet,
        Q,
        QuerySet,
        RecursiveDirection,
        RecursiveQuerySet,
        // Phase 8.5 djogi#180 — PG18 OLD/NEW RETURNING result type.
        // `ReturningPair<T>` carries both the before- and after-UPDATE row
        // snapshots; used by `Model::update_returning_pair` and
        // `UpdateStmt::execute_returning_pairs`.
        ReturningPair,
        SetOpKind,
        SetOpQuerySet,
        ValuesFieldRef,
        ValuesFields,
        ValuesJoinedQuerySet,
        ValuesOn,
        ValuesRow,
        ValuesScalar,
        VisageQuerySet,
    };
    // `atomic` / `atomic_with` / `retry_on_conflict` /
    // `retry_on_conflict_with_backoff` — Phase 4 Task 1 canonical transaction
    // scope + retry helper, plus the Phase 8.5 typed isolation-level surface
    // (#168), production backoff policy (#164), and typed deferred-constraints
    // scope (#169).
    pub use crate::transaction::{
        DeferScope, IsolationLevel, TransactionRetryBackoff, atomic, atomic_with,
        retry_on_conflict, retry_on_conflict_with_backoff,
    };
    pub use crate::visage::{DjogiVisage, VisageError};
    pub use djogi_macros::Model;
    // Relation wrappers — unresolved (`ForeignKey`, `OneToOneField`) are
    // what user model structs declare; resolved (`ForeignKeyResolved`,
    // `OneToOneFieldResolved`) are what prefetched view structs receive,
    // and `OnDelete` is used at the `#[field(on_delete = ...)]` site. All
    // five belong in the prelude because a model defining any relation
    // needs the unresolved wrapper, and any handler consuming a
    // prefetched row needs the resolved wrapper.
    pub use crate::primary_key::{PrimaryKey, PrimaryKeyClientGen, PrimaryKeyDbGen};
    pub use crate::relation::{
        ForeignKey, ForeignKeyResolved, JoinedRow, ManyToMany, OnDelete, OneToOneField,
        OneToOneFieldResolved, PrefetchedRow,
    };
    pub use crate::tracked::Tracked;
    pub use crate::types::{
        Date, DateTime, HeerId, HeerIdDesc, HeerIdRecencyBiased, Interval, Range, RangeBound,
        RanjId, RanjIdDesc, RanjIdRecencyBiased,
    };
    // djogi#213 — typed Postgres network types (`network` feature).
    // `IpAddr` lives in `std::net` and is not re-exported through the
    // prelude (it is stdlib, not djogi); adopters spell it
    // `std::net::IpAddr` at the field declaration site.
    #[cfg(feature = "network")]
    pub use crate::types::{CidrAddr, MacAddr};
    // T7 fixup — `DjogiVisageOf<M>` is the seal trait bounding every
    // `{Visage}` type to its source model `M`. Adopter code that writes
    // generic bounds over "any projection of M" names this trait, so it
    // belongs in the default prelude alongside `Model`.
    pub use crate::visage_boundary::DjogiVisageOf;
    // Re-export the `#[model]` attribute macro so that `use djogi::prelude::*`
    // is the only import a model definition needs.
    pub use djogi_macros::model;
    // Re-export the `djogi::apps!` function-like macro — required to declare
    // compile-time schema ownership domains (Phase 7-Zero v3 T7).
    pub use djogi_macros::apps;
    // Re-export the `djogi::primary_key!` function-like macro — lets
    // adopters declare custom PK newtypes (Phase 7-Zero-2 T3).
    pub use djogi_macros::primary_key;
    // Re-export the `#[djogi_test]` attribute macro for test functions.
    // The macro generates code that calls `::djogi::testing::setup_test_db`;
    // use only in test binaries.
    pub use djogi_macros::djogi_test;
    // Re-export the `#[derive(DjogiEnum)]` derive macro.
    pub use djogi_macros::DjogiEnum;
    // Re-export the `#[derive(JsonbSchema)]` derive macro.
    pub use djogi_macros::JsonbSchema;
    // Phase 8 §T2.6 — `#[derive(SoftDeletable)]` was retired in favour
    // of `#[model(soft_deletable)]` (mirrors the T2.4 Auditable pivot).
    // The runtime trait `SoftDeletable` re-export above (via
    // `crate::compose::*`) stays — only the derive surface goes away.
    // T11 / issue #30 — re-export the serde derives so `use djogi::prelude::*`
    // is sufficient for any `JsonbSchema`-deriving or `DjogiEnum`-deriving
    // type. The macro emits `#[derive(Serialize, Deserialize)]` paths through
    // `::djogi::__private::serde`, but adopter-side typed JSONB schemas
    // (`Jsonb<MyShape>`) derive serde directly on `MyShape`, and asking
    // adopters to add a `serde` line to their `Cargo.toml` and a separate
    // `use serde::*` clause is friction the framework can absorb.
    pub use ::serde::{Deserialize, Serialize};
    // Spatial primitives — gated behind the `spatial` feature flag.
    // `GeoPoint` covers per-row point geometries (lat/lon); `Polygon`
    // covers per-row polygonal geometries (convex hulls, territories,
    // service areas) used by the spatial aggregate surface
    // (`AggregateExpr<Polygon>` from `.convex_hull()`,
    // `.union()`/`.mem_union()`) and consumed by pair-tuple spatial
    // annotations (`PairAreaOverlapRatio<L, R>` over two
    // per-row polygon columns).
    #[cfg(feature = "spatial")]
    pub use crate::geo::{GeoPoint, Polygon};
    #[cfg(feature = "spatial")]
    pub use crate::query::{AsGeobufTerminal, AsMvtTerminal};
}