1use crate::doc::Doc;
9use crate::{Cell, Executor};
10use quarb::QueryResult;
11
12pub struct LocalExecutor {
13 doc: Doc,
14 now: (i64, u32),
16 allow_shell: bool,
17 model: Option<quarb_model::Model>,
20 #[cfg(feature = "native")]
24 respec: Option<(Vec<crate::MountSpec>, crate::Options)>,
25}
26
27impl LocalExecutor {
28 pub fn new(doc: Doc, now: (i64, u32), allow_shell: bool) -> Self {
30 Self {
31 doc,
32 now,
33 allow_shell,
34 #[cfg(feature = "native")]
35 respec: None,
36 model: None,
37 }
38 }
39
40 pub fn with_model(mut self, model: Option<quarb_model::Model>) -> Self {
43 self.model = model;
44 self
45 }
46
47 #[cfg(feature = "native")]
50 pub fn with_respec(
51 doc: Doc,
52 now: (i64, u32),
53 allow_shell: bool,
54 specs: Vec<crate::MountSpec>,
55 opts: crate::Options,
56 ) -> Self {
57 Self {
58 doc,
59 now,
60 allow_shell,
61 respec: Some((specs, opts)),
62 model: None,
63 }
64 }
65}
66
67fn run_doc(doc: &Doc, query: &str, now: (i64, u32), allow_shell: bool) -> anyhow::Result<Vec<Cell>> {
69 let result = doc
70 .run(query, now, allow_shell)
71 .map_err(|e| anyhow::anyhow!("{e}"))?;
72 Ok(match result {
73 QueryResult::Nodes(nodes) => nodes.into_iter().map(|n| Cell::Node(doc.render(n))).collect(),
74 QueryResult::Values(values) => values.into_iter().map(Cell::Value).collect(),
75 })
76}
77
78fn run_doc_modeled(
80 doc: &Doc,
81 query: &str,
82 now: (i64, u32),
83 allow_shell: bool,
84 model: &quarb_model::Model,
85) -> anyhow::Result<Vec<Cell>> {
86 let result = doc
87 .run_modeled(query, now, allow_shell, model)
88 .map_err(|e| anyhow::anyhow!("{e}"))?;
89 Ok(match result {
90 QueryResult::Nodes(nodes) => nodes
91 .into_iter()
92 .map(|n| Cell::Node(doc.render_modeled(n, model)))
93 .collect(),
94 QueryResult::Values(values) => values.into_iter().map(Cell::Value).collect(),
95 })
96}
97
98impl Executor for LocalExecutor {
99 fn run(&self, query: &str) -> anyhow::Result<Vec<Cell>> {
100 if let Some(model) = &self.model {
101 return run_doc_modeled(&self.doc, query, self.now, self.allow_shell, model);
102 }
103 run_doc(&self.doc, query, self.now, self.allow_shell)
104 }
105
106 fn run_fresh(&self, query: &str) -> anyhow::Result<Vec<Cell>> {
107 #[cfg(feature = "native")]
108 if let Some((specs, opts)) = &self.respec {
109 let fresh = match specs.as_slice() {
110 [one] if one.name.is_none() => Doc::open(&one.path, opts)?,
111 many => Doc::mount_specs(many, opts)?,
112 };
113 return run_doc(&fresh, query, self.now, self.allow_shell);
114 }
115 self.run(query)
116 }
117
118 fn export(&self, query: &str, kind: &str) -> anyhow::Result<String> {
119 if self.model.is_some() {
120 anyhow::bail!("rendered export over a --model session is not supported yet");
121 }
122 self.doc.export(query, self.now, self.allow_shell, kind)
123 }
124}