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
//! The per-dialect seam for the session store.
//!
//! The store is one implementation. Everything that genuinely differs between
//! PostgreSQL, SQLite, and MySQL 8 -- the statement text, the placeholder
//! style, the spelling of "now", the storage representation of an expiry, and
//! which of the three upsert grammars applies -- lives behind this module,
//! and nothing else in `crate::auth::session_store` mentions a driver by
//! name.
//!
//! # Why the upsert has three spellings
//!
//! Every dialect can write "insert this row, or overwrite the one already
//! there", and each spells it differently: PostgreSQL and SQLite take
//! `ON CONFLICT ... DO UPDATE`, MySQL takes `REPLACE INTO`. `REPLACE` is the
//! one that would be wrong on a table with a foreign key or an
//! auto-increment column, because it deletes the old row before inserting the
//! new one -- `arcature_sessions` has neither, and the alternative
//! (`ON DUPLICATE KEY UPDATE`) either binds the same two values twice or uses
//! the `VALUES()` function MySQL 8.0.20 deprecated. All three spellings take
//! the same three binds in the same order, so the Rust side stays one path.
use ;
use OffsetDateTime;
use SessionStoreError;
/// The SQLx database the store speaks. Chosen by the `db-*` features; the
/// mutual-exclusion check lives in [`crate::database`].
pub type SessionDb = crateDriver;
/// The connection pool the store runs over.
pub type SessionPool = cratePool;
/// How an expiry is stored in this dialect.
///
/// PostgreSQL and MySQL have real timestamp types and SQLx binds
/// `DateTime<Utc>` straight into them. SQLite has no timestamp type: a value
/// bound as text would have to be compared as text, and text comparison of
/// timestamps is only correct while every writer agrees on the format down to
/// the digit. Epoch milliseconds are compared as integers, which is correct
/// no matter who wrote the row.
pub type StoredTime = ;
/// How an expiry is stored in this dialect. See the PostgreSQL/MySQL variant
/// of this alias for why SQLite differs.
pub type StoredTime = i64;
/// Convert an expiry into this dialect's storage representation.
///
/// # Errors
///
/// Returns [`SessionStoreError::Expiry`] when the instant is outside the
/// range the column can hold. Reachable only from a caller that set an expiry
/// tens of thousands of years out, but silently storing a different instant
/// than the one asked for is how a session outlives its expiry.
pub
/// Convert an expiry into this dialect's storage representation.
///
/// SQLite stores epoch milliseconds, so sub-millisecond precision is dropped.
/// A session expiry is a wall-clock deadline minutes or hours away; a
/// millisecond either side of it is not a distinction the store is asked to
/// keep.
///
/// # Errors
///
/// Returns [`SessionStoreError::Expiry`] when the instant does not fit in an
/// `i64` of milliseconds.
pub
/// Read an expiry back out of this dialect's storage representation.
///
/// # Errors
///
/// Returns [`SessionStoreError::Expiry`] when the stored value is not a time
/// `OffsetDateTime` can represent, which means the row was written by
/// something other than this store.
pub
/// Read an expiry back out of this dialect's storage representation.
///
/// # Errors
///
/// Returns [`SessionStoreError::Expiry`] when the stored millisecond count is
/// not a time `OffsetDateTime` can represent.
pub
pub use sql;
pub use sql;
pub use sql;