Archived
d1ec384b27
- crates/ → engrams/ (Rust engrams live here) - bindings/ → receptors/ (cross-language access points into the graph) - Cargo.toml workspace paths updated
134 lines
4.2 KiB
Rust
134 lines
4.2 KiB
Rust
/// In-memory registry of named projection schemas.
|
|
///
|
|
/// The registry is the store of all registered projections. In a running server,
|
|
/// one registry instance is shared (behind a Mutex or RwLock). Projections are
|
|
/// looked up by name to execute queries.
|
|
use std::collections::HashMap;
|
|
|
|
use crate::error::{ProjectionError, ProjectionResult};
|
|
use crate::schema::ProjectionSchema;
|
|
|
|
/// Holds all registered `ProjectionSchema`s, keyed by name.
|
|
#[derive(Default)]
|
|
pub struct ProjectionRegistry {
|
|
schemas: HashMap<String, ProjectionSchema>,
|
|
}
|
|
|
|
impl ProjectionRegistry {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
schemas: HashMap::new(),
|
|
}
|
|
}
|
|
|
|
/// Register a new schema. Fails if one with the same name already exists.
|
|
pub fn register(&mut self, schema: ProjectionSchema) -> ProjectionResult<()> {
|
|
if self.schemas.contains_key(&schema.name) {
|
|
return Err(ProjectionError::AlreadyExists(schema.name.clone()));
|
|
}
|
|
if schema.name.is_empty() {
|
|
return Err(ProjectionError::InvalidSchema("name must not be empty".into()));
|
|
}
|
|
self.schemas.insert(schema.name.clone(), schema);
|
|
Ok(())
|
|
}
|
|
|
|
/// Replace an existing schema (upsert). Creates if not present.
|
|
pub fn upsert(&mut self, schema: ProjectionSchema) -> ProjectionResult<()> {
|
|
if schema.name.is_empty() {
|
|
return Err(ProjectionError::InvalidSchema("name must not be empty".into()));
|
|
}
|
|
self.schemas.insert(schema.name.clone(), schema);
|
|
Ok(())
|
|
}
|
|
|
|
/// Retrieve a schema by name.
|
|
pub fn get(&self, name: &str) -> ProjectionResult<&ProjectionSchema> {
|
|
self.schemas
|
|
.get(name)
|
|
.ok_or_else(|| ProjectionError::NotFound(name.to_string()))
|
|
}
|
|
|
|
/// List all schema names.
|
|
pub fn list(&self) -> Vec<&ProjectionSchema> {
|
|
let mut schemas: Vec<&ProjectionSchema> = self.schemas.values().collect();
|
|
schemas.sort_by(|a, b| a.name.cmp(&b.name));
|
|
schemas
|
|
}
|
|
|
|
/// Remove a schema by name. Returns true if it existed.
|
|
pub fn remove(&mut self, name: &str) -> bool {
|
|
self.schemas.remove(name).is_some()
|
|
}
|
|
|
|
/// Number of registered schemas.
|
|
pub fn len(&self) -> usize {
|
|
self.schemas.len()
|
|
}
|
|
|
|
/// True if no schemas are registered.
|
|
pub fn is_empty(&self) -> bool {
|
|
self.schemas.is_empty()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::schema::{NodeFilter, ProjectionType};
|
|
|
|
fn make_schema(name: &str) -> ProjectionSchema {
|
|
ProjectionSchema {
|
|
name: name.to_string(),
|
|
description: None,
|
|
projection_type: ProjectionType::Relational,
|
|
node_filter: NodeFilter::All,
|
|
field_mappings: vec![],
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_register_and_get() {
|
|
let mut reg = ProjectionRegistry::new();
|
|
reg.register(make_schema("users")).unwrap();
|
|
let s = reg.get("users").unwrap();
|
|
assert_eq!(s.name, "users");
|
|
}
|
|
|
|
#[test]
|
|
fn test_register_duplicate_fails() {
|
|
let mut reg = ProjectionRegistry::new();
|
|
reg.register(make_schema("events")).unwrap();
|
|
assert!(reg.register(make_schema("events")).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_upsert_replaces() {
|
|
let mut reg = ProjectionRegistry::new();
|
|
reg.register(make_schema("s1")).unwrap();
|
|
let mut updated = make_schema("s1");
|
|
updated.description = Some("updated".into());
|
|
reg.upsert(updated).unwrap();
|
|
assert_eq!(reg.get("s1").unwrap().description.as_deref(), Some("updated"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_list_sorted() {
|
|
let mut reg = ProjectionRegistry::new();
|
|
reg.register(make_schema("zoo")).unwrap();
|
|
reg.register(make_schema("alpha")).unwrap();
|
|
reg.register(make_schema("mango")).unwrap();
|
|
let names: Vec<&str> = reg.list().iter().map(|s| s.name.as_str()).collect();
|
|
assert_eq!(names, vec!["alpha", "mango", "zoo"]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_remove() {
|
|
let mut reg = ProjectionRegistry::new();
|
|
reg.register(make_schema("temp")).unwrap();
|
|
assert!(reg.remove("temp"));
|
|
assert!(!reg.remove("temp"));
|
|
assert!(reg.get("temp").is_err());
|
|
}
|
|
}
|