tank_core/lib.rs
1//! Core primitives for the `tank` ORM / query toolkit.
2//!
3//! This crate exposes a thin, async-first abstraction layer over SQL
4//! backends. The goal is portability – the same entity and query
5//! building code should compile and run against multiple SQL
6//! engines with minimal (ideally zero) changes.
7//!
8//! # Design Highlights
9//! * "Bring your own runtime" – traits return `impl Future` / `impl Stream`.
10//! You can use Tokio, async-std, or any executor capable of driving
11//! `futures` streams. This varies from driver to driver.
12//! * Streaming results (`Executor::run` / `fetch`) to avoid buffering entire
13//! result sets.
14//! * A rich `Value` enum representing typed SQL values (including arrays,
15//! maps, structs, intervals, decimals) with conversion helpers via `AsValue`.
16//! * Declarative entity definition through the `Entity` trait + derive macro.
17//! * Dialect pluggability: the `Driver` supplies a `SqlWriter` that renders
18//! the appropriate SQL for its backend.
19//! * Composability: expressions / datasets build larger statements (SELECT,
20//! INSERT, DELETE) without stringly-typed concatenation.
21//!
22//! # Quick Start
23//! ```rust,no_run
24//! use tank::{Entity, Executor};
25//! use uuid::Uuid;
26//!
27//! #[derive(tank::Entity)]
28//! #[tank(schema = "operations")]
29//! struct Operator {
30//! #[tank(primary_key)]
31//! id: Uuid,
32//! callsign: String,
33//! #[tank(name = "rank")]
34//! service_rank: String,
35//! }
36//!
37//! async fn demo<E: Executor>(exec: &mut E, id: Uuid) -> anyhow::Result<Option<Operator>> {
38//! // Ensure table exists (idempotent when supported by driver)
39//! Operator::create_table(exec, true, true).await?;
40//!
41//! // Upsert an operator
42//! Operator { id, callsign: "Red-One".into(), service_rank: "LT".into() }
43//! .save(exec).await?;
44//!
45//! // Fetch it back
46//! let op = Operator::find_one(exec, &true).await?; // bool implements Expression
47//! Ok(op)
48//! }
49//! ```
50//!
51//! # Error Handling
52//! All fallible operations use crate-level `Result<T>` (`anyhow::Result<T>`).
53//! For detailed context attachers prefer `ErrorContext`.
54//!
55//! # Futures & Streams MUST be driven
56//! Any method returning a future or stream performs no guaranteed side-effect
57//! until it is awaited / fully consumed. Never drop them silently.
58//!
59//! # Feature Flags
60//! Drivers may expose feature flags (e.g. disabling 128-bit integers). This
61//! crate itself is mostly feature-free; consult driver crates for details.
62//!
63//! # Modules
64//! The public surface re-exports most modules. Common entry points:
65//! * `Entity` – declare and persist typed rows.
66//! * `Executor` – run queries, fetch streams.
67//! * `Query`, `QueryResult` – represent prepared/raw statements & results.
68//! * `Value`, `AsValue` – value type system & conversions.
69//! * `SqlWriter` – backend SQL generation.
70//! * `Interval` – time span type usable as SQL INTERVAL.
71//! * `Join`, `Expression` – build complex predicates / SELECT trees.
72//!
73//! For more elaborate examples inspect the `tank-tests` crate in the
74//! repository (`src/simple.rs`, `src/transaction1.rs`, etc.).
75//!
76//! # Macros
77//! Supporting macros like `truncate_long!`, `possibly_parenthesized!` and
78//! `take_until!` assist with SQL / token generation. They are re-exported at
79//! crate root for macro expansion within derives.
80//!
81//! # Safety & Portability Notes
82//! * Do not rely on side-effects before awaiting returned futures.
83//! * Always exhaust streams if the driver might hold transactional or cursor
84//! resources.
85//! * When mapping `Value` conversions prefer `AsValue::try_from_value` for
86//! graceful errors.
87//!
88//! # Contributing Docs
89//! When adding new traits or types ensure they carry `///` rustdoc including:
90//! * Purpose & invariants
91//! * Example snippet (consider pulling from tests)
92//! * Error semantics
93//!
94mod as_value;
95mod column;
96mod connection;
97mod data_set;
98mod decode_type;
99mod driver;
100mod entity;
101mod executor;
102mod expression;
103mod interval;
104mod join;
105mod prepared;
106mod query;
107mod relations;
108mod table_ref;
109mod transaction;
110mod util;
111mod value;
112mod writer;
113
114pub use ::anyhow::Context as ErrorContext;
115pub use as_value::*;
116pub use column::*;
117pub use connection::*;
118pub use data_set::*;
119pub use decode_type::*;
120pub use driver::*;
121pub use entity::*;
122pub use executor::*;
123pub use expression::*;
124pub use interval::*;
125pub use join::*;
126pub use prepared::*;
127pub use query::*;
128pub use relations::*;
129pub use table_ref::*;
130pub use transaction::*;
131pub use util::*;
132pub use value::*;
133pub use writer::*;
134pub mod stream {
135 pub use ::futures::stream::*;
136}
137pub use ::futures::future;
138pub use ::futures::sink;
139
140/// Crate-wide result alias using `anyhow` for flexible error context.
141pub type Result<T> = anyhow::Result<T>;
142/// Crate-wide error alias using `anyhow`.
143pub type Error = anyhow::Error;
144
145pub use ::indoc;