@@ -8,18 +8,20 @@ use std::time::Duration;
8
8
///
9
9
/// ```rust
10
10
/// use async_sqlx_session::SqliteStore;
11
- /// use async_session::SessionStore;
11
+ /// use async_session::{Session, SessionStore};
12
+ /// use std::time::Duration;
13
+ ///
12
14
/// # fn main() -> async_session::Result { async_std::task::block_on(async {
13
15
/// let store = SqliteStore::new("sqlite:%3Amemory:").await?;
14
16
/// store.migrate().await?;
15
- /// store.spawn_cleanup_task(std::time:: Duration::from_secs(60 * 60));
17
+ /// store.spawn_cleanup_task(Duration::from_secs(60 * 60));
16
18
///
17
- /// let mut session = async_session:: Session::new();
19
+ /// let session = Session::new();
18
20
/// session.insert("key".into(), "value".into());
19
21
///
20
22
/// let cookie_value = store.store_session(session).await.unwrap();
21
23
/// let session = store.load_session(cookie_value).await.unwrap();
22
- /// assert_eq!(session.get("key"), Some( "value".to_owned()) );
24
+ /// assert_eq!(session.get("key").unwrap(), "value");
23
25
/// # Ok(()) }) }
24
26
///
25
27
#[ derive( Clone , Debug ) ]
@@ -51,9 +53,12 @@ impl SqliteStore {
51
53
}
52
54
}
53
55
54
- /// constructs a new SqliteStore from a sqlite: database url. the
55
- /// default table name for this session store will be
56
- /// "async_sessions". To override this, either chain with
56
+ /// Constructs a new SqliteStore from a sqlite: database url. note
57
+ /// that this documentation uses the special `:memory:` sqlite
58
+ /// database for convenient testing, but a real application would
59
+ /// use a path like `sqlite:///path/to/database.db`. The default
60
+ /// table name for this session store will be "async_sessions". To
61
+ /// override this, either chain with
57
62
/// [`with_table_name`](crate::SqliteStore::with_table_name) or
58
63
/// use
59
64
/// [`new_with_table_name`](crate::SqliteStore::new_with_table_name)
@@ -62,8 +67,7 @@ impl SqliteStore {
62
67
/// # use async_sqlx_session::SqliteStore;
63
68
/// # use async_session::Result;
64
69
/// # fn main() -> Result { async_std::task::block_on(async {
65
- /// let store = SqliteStore::new("sqlite:%3Amemory:").await?
66
- /// .with_table_name("custom_table_name");
70
+ /// let store = SqliteStore::new("sqlite:%3Amemory:").await?;
67
71
/// store.migrate().await;
68
72
/// # Ok(()) }) }
69
73
/// ```
@@ -92,6 +96,24 @@ impl SqliteStore {
92
96
93
97
/// Chainable method to add a custom table name. This will panic
94
98
/// if the table name is not `[a-zA-Z0-9_-]+`.
99
+ /// ```rust
100
+ /// # use async_sqlx_session::SqliteStore;
101
+ /// # use async_session::Result;
102
+ /// # fn main() -> Result { async_std::task::block_on(async {
103
+ /// let store = SqliteStore::new("sqlite:%3Amemory:").await?
104
+ /// .with_table_name("custom_name");
105
+ /// store.migrate().await;
106
+ /// # Ok(()) }) }
107
+ /// ```
108
+ ///
109
+ /// ```should_panic
110
+ /// # use async_sqlx_session::SqliteStore;
111
+ /// # use async_session::Result;
112
+ /// # fn main() -> Result { async_std::task::block_on(async {
113
+ /// let store = SqliteStore::new("sqlite:%3Amemory:").await?
114
+ /// .with_table_name("johnny (); drop users;");
115
+ /// # Ok(()) }) }
116
+ /// ```
95
117
pub fn with_table_name ( mut self , table_name : impl AsRef < str > ) -> Self {
96
118
let table_name = table_name. as_ref ( ) ;
97
119
if table_name. is_empty ( )
@@ -114,6 +136,18 @@ impl SqliteStore {
114
136
/// store initialization. In the future, this may make
115
137
/// exactly-once modifications to the schema of the session table
116
138
/// on breaking releases.
139
+ /// ```rust
140
+ /// # use async_sqlx_session::SqliteStore;
141
+ /// # use async_session::{Result, SessionStore, Session};
142
+ /// # fn main() -> Result { async_std::task::block_on(async {
143
+ /// let store = SqliteStore::new("sqlite:%3Amemory:").await?;
144
+ /// assert!(store.count().await.is_err());
145
+ /// store.migrate().await?;
146
+ /// store.store_session(Session::new()).await;
147
+ /// store.migrate().await?; // calling it a second time is safe
148
+ /// assert_eq!(store.count().await?, 1);
149
+ /// # Ok(()) }) }
150
+ /// ```
117
151
pub async fn migrate ( & self ) -> sqlx:: Result < ( ) > {
118
152
log:: info!( "migrating sessions on `{}`" , self . table_name) ;
119
153
@@ -132,16 +166,35 @@ impl SqliteStore {
132
166
Ok ( ( ) )
133
167
}
134
168
169
+ // private utility function because sqlite does not support
170
+ // parametrized table names
135
171
fn substitute_table_name ( & self , query : & str ) -> String {
136
172
query. replace ( "%%TABLE_NAME%%" , & self . table_name )
137
173
}
138
174
175
+ /// retrieve a connection from the pool
139
176
async fn connection ( & self ) -> sqlx:: Result < PoolConnection < SqliteConnection > > {
140
177
self . client . acquire ( ) . await
141
178
}
142
179
143
180
/// Spawns an async_std::task that clears out stale (expired)
144
181
/// sessions on a periodic basis.
182
+ /// ```rust
183
+ /// # use async_sqlx_session::SqliteStore;
184
+ /// # use async_session::{Result, SessionStore, Session};
185
+ /// # use std::time::Duration;
186
+ /// # fn main() -> Result { async_std::task::block_on(async {
187
+ /// let store = SqliteStore::new("sqlite:%3Amemory:").await?;
188
+ /// store.migrate().await?;
189
+ /// store.spawn_cleanup_task(Duration::from_secs(1));
190
+ /// let mut session = Session::new();
191
+ /// session.expire_in(Duration::from_secs(0));
192
+ /// store.store_session(session).await;
193
+ /// assert_eq!(store.count().await?, 1);
194
+ /// async_std::task::sleep(Duration::from_secs(2)).await;
195
+ /// assert_eq!(store.count().await?, 0);
196
+ /// # Ok(()) }) }
197
+ /// ```
145
198
pub fn spawn_cleanup_task ( & self , period : Duration ) -> task:: JoinHandle < ( ) > {
146
199
let store = self . clone ( ) ;
147
200
task:: spawn ( async move {
@@ -156,6 +209,20 @@ impl SqliteStore {
156
209
157
210
/// Performs a one-time cleanup task that clears out stale
158
211
/// (expired) sessions. You may want to call this from cron.
212
+ /// ```rust
213
+ /// # use async_sqlx_session::SqliteStore;
214
+ /// # use async_session::{chrono::{Utc,Duration}, Result, SessionStore, Session};
215
+ /// # fn main() -> Result { async_std::task::block_on(async {
216
+ /// let store = SqliteStore::new("sqlite:%3Amemory:").await?;
217
+ /// store.migrate().await?;
218
+ /// let mut session = Session::new();
219
+ /// session.set_expiry(Utc::now() - Duration::seconds(5));
220
+ /// store.store_session(session).await;
221
+ /// assert_eq!(store.count().await?, 1);
222
+ /// store.cleanup().await?;
223
+ /// assert_eq!(store.count().await?, 0);
224
+ /// # Ok(()) }) }
225
+ /// ```
159
226
pub async fn cleanup ( & self ) -> sqlx:: Result < ( ) > {
160
227
let mut connection = self . connection ( ) . await ?;
161
228
sqlx:: query ( & self . substitute_table_name (
@@ -171,10 +238,27 @@ impl SqliteStore {
171
238
Ok ( ( ) )
172
239
}
173
240
241
+ /// retrieves the number of sessions currently stored, including
242
+ /// expired sessions
243
+ ///
244
+ /// ```rust
245
+ /// # use async_sqlx_session::SqliteStore;
246
+ /// # use async_session::{Result, SessionStore, Session};
247
+ /// # use std::time::Duration;
248
+ /// # fn main() -> Result { async_std::task::block_on(async {
249
+ /// let store = SqliteStore::new("sqlite:%3Amemory:").await?;
250
+ /// store.migrate().await?;
251
+ /// assert_eq!(store.count().await?, 0);
252
+ /// store.store_session(Session::new()).await;
253
+ /// assert_eq!(store.count().await?, 1);
254
+ /// # Ok(()) }) }
255
+ /// ```
256
+
174
257
pub async fn count ( & self ) -> sqlx:: Result < i32 > {
175
- let ( count, ) = sqlx:: query_as ( "select count(*) from async_sessions" )
176
- . fetch_one ( & mut self . connection ( ) . await ?)
177
- . await ?;
258
+ let ( count, ) =
259
+ sqlx:: query_as ( & self . substitute_table_name ( "SELECT COUNT(*) FROM %%TABLE_NAME%%" ) )
260
+ . fetch_one ( & mut self . connection ( ) . await ?)
261
+ . await ?;
178
262
179
263
Ok ( count)
180
264
}
0 commit comments