1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//! [`VistaResolver`]: the one way to turn a name into a [`Vista`].
use vantage_core::Result;
use crate::vista::Vista;
/// Builds the [`Vista`] a name stands for: a model in a
/// [`Catalog`](crate::Catalog), a relation's bare target, a table a script
/// names.
///
/// Each call returns a fresh, un-narrowed Vista the caller owns. A name the
/// resolver doesn't know is an error marked
/// [`not_found`](vantage_core::VantageError::is_not_found); any other failure
/// (a backend that can't be reached, a model that doesn't build) keeps its
/// own kind, so a caller can tell a missing name from an unreachable one.
///
/// Any `Fn(&str) -> Result<Vista>` closure is a resolver. A host keeps one
/// as `Arc<dyn VistaResolver>`.
pub trait VistaResolver: Send + Sync {
fn vista(&self, name: &str) -> Result<Vista>;
}
impl<F: Fn(&str) -> Result<Vista> + Send + Sync> VistaResolver for F {
fn vista(&self, name: &str) -> Result<Vista> {
self(name)
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use vantage_core::error;
use super::*;
use crate::mocks::MockShell;
#[test]
fn a_closure_is_a_resolver() {
let resolver: Arc<dyn VistaResolver> = Arc::new(|name: &str| match name {
"user" => Ok(Vista::new(name, MockShell::new())),
_ => Err(error!("no such table", name = name).mark_not_found()),
});
assert_eq!(resolver.vista("user").unwrap().name(), "user");
assert!(resolver.vista("nope").unwrap_err().is_not_found());
}
}