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    pub fn insert(&mut self, key: impl Into<String>, value: impl Into<String>) {
24        let key = key.into();
25        let value = value.into();
26        if let Some(entry) = self.entries.iter_mut().find(|(k, _)| *k == key) {
27            entry.1 = value;
28        } else {
29            self.entries.push((key, value));
30        }
31    }
32
33    #[must_use]
34    pub fn get(&self, key: &str) -> Option<&str> {
35        self.entries
36            .iter()
37            .find(|(k, _)| k == key)
38            .map(|(_, v)| v.as_str())
39    }
40
41    #[must_use]
42    pub const fn is_empty(&self) -> bool {
43        self.entries.is_empty()
44    }
45
46    pub fn iter(&self) -> impl Iterator<Item = (&str, &str)> {
47        self.entries.iter().map(|(k, v)| (k.as_str(), v.as_str()))
48    }
49}