mirror of
https://github.com/actix/actix-extras.git
synced 2025-03-16 18:32:43 +01:00
implement contains_key, update, update_or
This commit is contained in:
parent
48646d1bd3
commit
d1639b93cd
actix-session
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- Add `session.update(key, updater)`
|
||||||
|
- Add `session.update_or(key, updater, default_value)`
|
||||||
|
- Add `session.contains_key(key)`
|
||||||
|
|
||||||
## 0.10.0
|
## 0.10.0
|
||||||
|
|
||||||
- Add `redis-session-rustls` crate feature that enables `rustls`-secured Redis sessions.
|
- Add `redis-session-rustls` crate feature that enables `rustls`-secured Redis sessions.
|
||||||
|
@ -32,6 +32,8 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||||||
/// } else {
|
/// } else {
|
||||||
/// session.insert("counter", 1)?;
|
/// session.insert("counter", 1)?;
|
||||||
/// }
|
/// }
|
||||||
|
/// // Or use the shorthand
|
||||||
|
/// session.update_or("counter", |count: i32| count + 1, 1);
|
||||||
///
|
///
|
||||||
/// Ok("Welcome!")
|
/// Ok("Welcome!")
|
||||||
/// }
|
/// }
|
||||||
@ -97,6 +99,13 @@ impl Session {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if a key exists on the session.
|
||||||
|
///
|
||||||
|
/// It returns true if the session contains a vaue for the specified key.
|
||||||
|
pub fn contains_key(&self, key: &str) -> bool {
|
||||||
|
self.0.borrow().state.contains_key(key)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get all raw key-value data from the session.
|
/// Get all raw key-value data from the session.
|
||||||
///
|
///
|
||||||
/// Note that values are JSON encoded.
|
/// Note that values are JSON encoded.
|
||||||
@ -145,6 +154,83 @@ impl Session {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates a key-value pair into the session.
|
||||||
|
///
|
||||||
|
/// If the key exists then update it to the new value and place it back in.
|
||||||
|
///
|
||||||
|
/// If the key does not exist it will not be updated.
|
||||||
|
///
|
||||||
|
/// Any serializable value can be used and will be encoded as JSON in session data, hence why
|
||||||
|
/// only a reference to the value is taken.
|
||||||
|
///
|
||||||
|
/// It returns an error if it fails to serialize `value` to JSON.
|
||||||
|
pub fn update<T: Serialize + DeserializeOwned, F>(
|
||||||
|
&self,
|
||||||
|
key: impl Into<String>,
|
||||||
|
updater: F,
|
||||||
|
) -> Result<(), SessionUpdateError>
|
||||||
|
where
|
||||||
|
F: FnOnce(T) -> T,
|
||||||
|
{
|
||||||
|
let mut inner = self.0.borrow_mut();
|
||||||
|
let key_str = key.into();
|
||||||
|
|
||||||
|
if let Some(val_str) = inner.state.get(&key_str) {
|
||||||
|
let value = serde_json::from_str(val_str)
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"Failed to deserialize the JSON-encoded session data attached to key \
|
||||||
|
`{}` as a `{}` type",
|
||||||
|
key_str,
|
||||||
|
std::any::type_name::<T>()
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map_err(SessionUpdateError)?;
|
||||||
|
|
||||||
|
let val = serde_json::to_string(&updater(value))
|
||||||
|
.with_context(|| {
|
||||||
|
format!(
|
||||||
|
"Failed to serialize the provided `{}` type instance as JSON in order to \
|
||||||
|
attach as session data to the `{}` key",
|
||||||
|
std::any::type_name::<T>(),
|
||||||
|
key_str
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map_err(SessionUpdateError)?;
|
||||||
|
|
||||||
|
inner.state.insert(key_str, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates a key-value pair into the session, or inserts a default value.
|
||||||
|
///
|
||||||
|
/// If the key exists then update it to the new value and place it back in.
|
||||||
|
///
|
||||||
|
/// If the key does not exist the default value will be inserted instead.
|
||||||
|
///
|
||||||
|
/// Any serializable value can be used and will be encoded as JSON in session data, hence why
|
||||||
|
/// only a reference to the value is taken.
|
||||||
|
///
|
||||||
|
/// It returns an error if it fails to serialize `value` to JSON.
|
||||||
|
pub fn update_or<T: Serialize + DeserializeOwned, F>(
|
||||||
|
&self,
|
||||||
|
key: &str,
|
||||||
|
updater: F,
|
||||||
|
default_value: T,
|
||||||
|
) -> Result<(), SessionUpdateError>
|
||||||
|
where
|
||||||
|
F: FnOnce(T) -> T,
|
||||||
|
{
|
||||||
|
if self.contains_key(key) {
|
||||||
|
self.update(key, updater)
|
||||||
|
} else {
|
||||||
|
self.insert(key, default_value)
|
||||||
|
.map_err(|e| SessionUpdateError(e.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Remove value from the session.
|
/// Remove value from the session.
|
||||||
///
|
///
|
||||||
/// If present, the JSON encoded value is returned.
|
/// If present, the JSON encoded value is returned.
|
||||||
@ -308,6 +394,11 @@ impl ResponseError for SessionGetError {
|
|||||||
#[display("{_0}")]
|
#[display("{_0}")]
|
||||||
pub struct SessionInsertError(anyhow::Error);
|
pub struct SessionInsertError(anyhow::Error);
|
||||||
|
|
||||||
|
/// Error returned by [`Session::update`].
|
||||||
|
#[derive(Debug, Display, From)]
|
||||||
|
#[display("{_0}")]
|
||||||
|
pub struct SessionUpdateError(anyhow::Error);
|
||||||
|
|
||||||
impl StdError for SessionInsertError {
|
impl StdError for SessionInsertError {
|
||||||
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||||
Some(self.0.as_ref())
|
Some(self.0.as_ref())
|
||||||
|
@ -69,6 +69,16 @@ async fn session_entries() {
|
|||||||
map.contains_key("test_num");
|
map.contains_key("test_num");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn session_contains_key() {
|
||||||
|
let req = test::TestRequest::default().to_srv_request();
|
||||||
|
let session = req.get_session();
|
||||||
|
session.insert("test_str", "val").unwrap();
|
||||||
|
session.insert("test_str", 1).unwrap();
|
||||||
|
assert!(session.contains_key("test_str"));
|
||||||
|
assert!(!session.contains_key("test_num"));
|
||||||
|
}
|
||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn insert_session_after_renew() {
|
async fn insert_session_after_renew() {
|
||||||
let session = test::TestRequest::default().to_srv_request().get_session();
|
let session = test::TestRequest::default().to_srv_request().get_session();
|
||||||
@ -83,6 +93,35 @@ async fn insert_session_after_renew() {
|
|||||||
assert_eq!(session.status(), SessionStatus::Renewed);
|
assert_eq!(session.status(), SessionStatus::Renewed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn update_session() {
|
||||||
|
let session = test::TestRequest::default().to_srv_request().get_session();
|
||||||
|
|
||||||
|
session.update("test_val", |c: u32| c + 1).unwrap();
|
||||||
|
assert_eq!(session.status(), SessionStatus::Unchanged);
|
||||||
|
|
||||||
|
session.insert("test_val", 0).unwrap();
|
||||||
|
assert_eq!(session.status(), SessionStatus::Changed);
|
||||||
|
|
||||||
|
session.update("test_val", |c: u32| c + 1).unwrap();
|
||||||
|
assert_eq!(session.get("test_val").unwrap(), Some(1));
|
||||||
|
|
||||||
|
session.update("test_val", |c: u32| c + 1).unwrap();
|
||||||
|
assert_eq!(session.get("test_val").unwrap(), Some(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn update_or_session() {
|
||||||
|
let session = test::TestRequest::default().to_srv_request().get_session();
|
||||||
|
|
||||||
|
session.update_or("test_val", |c: u32| c + 1, 1).unwrap();
|
||||||
|
assert_eq!(session.status(), SessionStatus::Changed);
|
||||||
|
assert_eq!(session.get("test_val").unwrap(), Some(1));
|
||||||
|
|
||||||
|
session.update_or("test_val", |c: u32| c + 1, 1).unwrap();
|
||||||
|
assert_eq!(session.get("test_val").unwrap(), Some(2));
|
||||||
|
}
|
||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn remove_session_after_renew() {
|
async fn remove_session_after_renew() {
|
||||||
let session = test::TestRequest::default().to_srv_request().get_session();
|
let session = test::TestRequest::default().to_srv_request().get_session();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user