franken_snowflake_sqlapi/lib.rs
1//! `franken-snowflake-sqlapi` — the Snowflake SQL API protocol heart.
2//!
3//! This crate owns the *protocol data*: the request/response schemas, the
4//! `jsonv2` wire codec, and the HTTP-status response classification. It is pure
5//! and `serde`-driven — **no `asupersync`, no live network**. The cancel-correct
6//! statement lifecycle (`bracket` over submit/poll/partition/cancel) and the
7//! HTTPS transport land in the sibling beads `fsnow-statement-lifecycle-ofl` and
8//! `fsnow-asupersync-native-https-ofq`; this crate gives them the typed payloads
9//! and the status state machine to act on.
10//!
11//! Modules:
12//!
13//! - [`request`] — `POST /api/v2/statements` body: [`request::SubmitStatementRequest`],
14//! positional typed [`request::Binding`]s, and session [`request::SubmitQueryParams`].
15//! - [`response`] — the response bodies, one per HTTP status: a 200
16//! [`response::ResultSet`], a 202 [`response::QueryStatus`], a 408/422
17//! [`response::QueryFailureStatus`], and the [`response::StatementCancelResponse`],
18//! plus [`response::ResultSetMetaData`] / [`response::ColumnType`] /
19//! [`response::PartitionInfo`].
20//! - [`status`] — [`status::ResponseClass`]: the 200/202/408/422/429 routing
21//! state machine, kept distinct so no two states are ever conflated.
22//! - [`wire`] — the [`wire::CellValue`] `jsonv2` codec: every `data` cell is a
23//! JSON string decoded per its [`response::ColumnType`], never by JSON shape.
24//!
25//! ## Protocol references
26//!
27//! Behavioral source: Snowflake's official SQL API docs (clean-room — docs +
28//! live observation + our own fixtures only). Consulted 2026-06-24:
29//! `developer-guide/sql-api/{index,reference,submitting-requests,handling-responses}`.
30//! See `docs/protocol/schema_draft.md` for the field-by-field rationale and
31//! `docs/proof_lanes.md` (Lane 1) for the proof obligations these types satisfy.
32
33pub mod driver;
34pub mod lifecycle;
35pub mod request;
36pub mod response;
37pub mod status;
38pub mod wire;
39
40/// Crate version string.
41pub const VERSION: &str = env!("CARGO_PKG_VERSION");
42
43/// The SQL API base paths, relative to the account host
44/// (`<account>.snowflakecomputing.com`). The transport crate joins these with the
45/// host and the query string (`requestId`, `retry`, `async`, `partition`,
46/// `nullable`).
47pub mod endpoints {
48 /// `POST` here to submit a statement.
49 pub const SUBMIT: &str = "/api/v2/statements";
50
51 /// Build the per-handle status/result path: `GET` for poll/fetch.
52 #[must_use]
53 pub fn statement(handle: &str) -> String {
54 format!("/api/v2/statements/{handle}")
55 }
56
57 /// Build the per-handle cancel path: `POST` to cancel.
58 #[must_use]
59 pub fn cancel(handle: &str) -> String {
60 format!("/api/v2/statements/{handle}/cancel")
61 }
62}
63
64#[cfg(test)]
65mod redaction_drift_tests {
66 use std::collections::BTreeSet;
67
68 /// `franken-snowflake-auth` re-declares the secret-needle list because its
69 /// build script `include!`s that file for the credential-`Debug`-leak gate and
70 /// a build script cannot depend on `core`. This crate is the only one that
71 /// links both, so it fails CI if the two lists ever drift apart — a missing
72 /// prefix would silently leave a whole secret class un-redacted on one path.
73 #[test]
74 fn secret_needle_lists_do_not_drift() {
75 let core: BTreeSet<&str> = franken_snowflake_core::redact::SECRET_PREFIXES
76 .iter()
77 .copied()
78 .collect();
79 let auth: BTreeSet<&str> = franken_snowflake_auth::SECRET_VALUE_NEEDLE_PREFIXES
80 .iter()
81 .copied()
82 .collect();
83 assert_eq!(
84 core, auth,
85 "core::redact::SECRET_PREFIXES and auth::SECRET_VALUE_NEEDLE_PREFIXES drifted"
86 );
87 }
88}