Skip to main content

systemprompt_models/
scope.rs

1//! Per-request scoping identity carried from middleware to scoped database
2//! transactions.
3//!
4//! A [`RequestScope`] is dumb data: ordered key/value pairs an extension's
5//! middleware populates (for example the requesting user's organization) and a
6//! `ConnectionScopeProvider` in `systemprompt-database` later translates into
7//! transaction-local Postgres settings for row-level security.
8//!
9//! Copyright (c) systemprompt.io — Business Source License 1.1.
10//! See <https://systemprompt.io> for licensing details.
11
12#[derive(Debug, Clone, Default, PartialEq, Eq)]
13pub struct RequestScope {
14    entries: Vec<(String, String)>,
15}
16
17impl RequestScope {
18    #[must_use]
19    pub fn new() -> Self {
20        Self::default()
21    }
22
23    /// Insert or replace the value for `key`.
24    pub fn insert(&mut self, key: impl Into<String>, value: impl Into<String>) {
25        let key = key.into();
26        let value = value.into();
27        if let Some(entry) = self.entries.iter_mut().find(|(k, _)| *k == key) {
28            entry.1 = value;
29        } else {
30            self.entries.push((key, value));
31        }
32    }
33
34    #[must_use]
35    pub fn get(&self, key: &str) -> Option<&str> {
36        self.entries
37            .iter()
38            .find(|(k, _)| k == key)
39            .map(|(_, v)| v.as_str())
40    }
41
42    #[must_use]
43    pub const fn is_empty(&self) -> bool {
44        self.entries.is_empty()
45    }
46
47    pub fn iter(&self) -> impl Iterator<Item = (&str, &str)> {
48        self.entries.iter().map(|(k, v)| (k.as_str(), v.as_str()))
49    }
50}