Skip to content

Commit 423a88a

Browse files
authored
Merge pull request #2780 from fermyon/sqlite-statements
Run sqlite statements
2 parents d156648 + b5cd1d7 commit 423a88a

File tree

11 files changed

+292
-36
lines changed

11 files changed

+292
-36
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,6 @@ error: the `wasm32-wasi` target is not installed
6868
std::fs::create_dir_all("target/test-programs").unwrap();
6969

7070
build_wasm_test_program("core-wasi-test.wasm", "crates/core/tests/core-wasi-test");
71-
// build_wasm_test_program("redis-rust.wasm", "crates/trigger-redis/tests/rust");
72-
// build_wasm_test_program(
73-
// "spin-http-benchmark.wasm",
74-
// "crates/trigger-http/benches/spin-http-benchmark",
75-
// );
76-
// build_wasm_test_program(
77-
// "wagi-benchmark.wasm",
78-
// "crates/trigger-http/benches/wagi-benchmark",
79-
// );
80-
// build_wasm_test_program("timer_app_example.wasm", "examples/spin-timer/app-example");
8171

8272
cargo_build(TIMER_TRIGGER_INTEGRATION_TEST);
8373
}

crates/factor-sqlite/src/host.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,12 @@ impl v2::HostConnection for InstanceState {
6666
if !self.allowed_databases.contains(&database) {
6767
return Err(v2::Error::AccessDenied);
6868
}
69-
(self.get_connection_creator)(&database)
69+
let conn = (self.get_connection_creator)(&database)
7070
.ok_or(v2::Error::NoSuchDatabase)?
71-
.create_connection()
72-
.await
73-
.and_then(|conn| {
74-
self.connections
75-
.push(conn)
76-
.map_err(|()| v2::Error::Io("too many connections opened".to_string()))
77-
})
71+
.create_connection()?;
72+
self.connections
73+
.push(conn)
74+
.map_err(|()| v2::Error::Io("too many connections opened".to_string()))
7875
.map(Resource::new_own)
7976
}
8077

crates/factor-sqlite/src/lib.rs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,7 @@ impl Factor for SqliteFactor {
8181
get_connection_creator(label).is_some()
8282
})?;
8383

84-
Ok(AppState {
85-
allowed_databases,
86-
get_connection_creator,
87-
})
84+
Ok(AppState::new(allowed_databases, get_connection_creator))
8885
}
8986

9087
fn prepare<T: spin_factors::RuntimeFactors>(
@@ -149,28 +146,51 @@ pub trait DefaultLabelResolver: Send + Sync {
149146
fn default(&self, label: &str) -> Option<Arc<dyn ConnectionCreator>>;
150147
}
151148

149+
#[derive(Clone)]
152150
pub struct AppState {
153151
/// A map from component id to a set of allowed database labels.
154152
allowed_databases: HashMap<String, Arc<HashSet<String>>>,
155153
/// A function for mapping from database name to a connection creator.
156154
get_connection_creator: host::ConnectionCreatorGetter,
157155
}
158156

157+
impl AppState {
158+
/// Create a new `AppState`
159+
pub fn new(
160+
allowed_databases: HashMap<String, Arc<HashSet<String>>>,
161+
get_connection_creator: host::ConnectionCreatorGetter,
162+
) -> Self {
163+
Self {
164+
allowed_databases,
165+
get_connection_creator,
166+
}
167+
}
168+
169+
/// Get a connection for a given database label.
170+
///
171+
/// Returns `None` if there is no connection creator for the given label.
172+
pub async fn get_connection(
173+
&self,
174+
label: &str,
175+
) -> Option<Result<Box<dyn Connection>, v2::Error>> {
176+
let connection = (self.get_connection_creator)(label)?.create_connection();
177+
Some(connection)
178+
}
179+
}
180+
159181
/// A creator of a connections for a particular SQLite database.
160-
#[async_trait]
161182
pub trait ConnectionCreator: Send + Sync {
162183
/// Get a *new* [`Connection`]
163184
///
164185
/// The connection should be a new connection, not a reused one.
165-
async fn create_connection(&self) -> Result<Box<dyn Connection + 'static>, v2::Error>;
186+
fn create_connection(&self) -> Result<Box<dyn Connection + 'static>, v2::Error>;
166187
}
167188

168-
#[async_trait::async_trait]
169189
impl<F> ConnectionCreator for F
170190
where
171191
F: Fn() -> anyhow::Result<Box<dyn Connection + 'static>> + Send + Sync + 'static,
172192
{
173-
async fn create_connection(&self) -> Result<Box<dyn Connection + 'static>, v2::Error> {
193+
fn create_connection(&self) -> Result<Box<dyn Connection + 'static>, v2::Error> {
174194
(self)().map_err(|_| v2::Error::InvalidConnection)
175195
}
176196
}

crates/factor-sqlite/tests/factor_test.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,8 @@ impl spin_factor_sqlite::DefaultLabelResolver for DefaultLabelResolver {
143143
/// A connection creator that always returns an error.
144144
struct InvalidConnectionCreator;
145145

146-
#[async_trait::async_trait]
147146
impl spin_factor_sqlite::ConnectionCreator for InvalidConnectionCreator {
148-
async fn create_connection(
147+
fn create_connection(
149148
&self,
150149
) -> Result<Box<dyn spin_factor_sqlite::Connection + 'static>, spin_world::v2::sqlite::Error>
151150
{

crates/factors-executor/src/lib.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@ impl<T: RuntimeFactors, U: Send + 'static> FactorsExecutor<T, U> {
3232
hooks: Default::default(),
3333
})
3434
}
35+
}
3536

37+
impl<T: RuntimeFactors, U: Send + 'static> FactorsExecutor<T, U>
38+
where
39+
T::AppState: Sync,
40+
{
3641
/// Adds the given [`ExecutorHooks`] to this executor.
3742
///
3843
/// Hooks are run in the order they are added.
@@ -53,7 +58,7 @@ impl<T: RuntimeFactors, U: Send + 'static> FactorsExecutor<T, U> {
5358
.context("failed to configure app")?;
5459

5560
for hooks in &mut self.hooks {
56-
hooks.configure_app(&configured_app)?;
61+
hooks.configure_app(&configured_app).await?;
5762
}
5863

5964
let mut component_instance_pres = HashMap::new();
@@ -75,9 +80,14 @@ impl<T: RuntimeFactors, U: Send + 'static> FactorsExecutor<T, U> {
7580
}
7681
}
7782

78-
pub trait ExecutorHooks<T: RuntimeFactors, U>: Send + Sync {
83+
#[async_trait]
84+
pub trait ExecutorHooks<T, U>: Send + Sync
85+
where
86+
T: RuntimeFactors,
87+
T::AppState: Sync,
88+
{
7989
/// Configure app hooks run immediately after [`RuntimeFactors::configure_app`].
80-
fn configure_app(&mut self, configured_app: &ConfiguredApp<T>) -> anyhow::Result<()> {
90+
async fn configure_app(&mut self, configured_app: &ConfiguredApp<T>) -> anyhow::Result<()> {
8191
let _ = configured_app;
8292
Ok(())
8393
}
@@ -131,7 +141,12 @@ impl<T: RuntimeFactors, U: Send + 'static> FactorsExecutorApp<T, U> {
131141
.with_context(|| format!("no such component {component_id:?}"))?;
132142
Ok(instance_pre.component())
133143
}
144+
}
134145

146+
impl<T: RuntimeFactors, U: Send + 'static> FactorsExecutorApp<T, U>
147+
where
148+
T::AppState: Sync,
149+
{
135150
/// Returns an instance builder for the given component ID.
136151
pub fn prepare(&self, component_id: &str) -> anyhow::Result<FactorsInstanceBuilder<T, U>> {
137152
let app_component = self

crates/trigger/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,12 @@ spin-factors-executor = { path = "../factors-executor" }
4242
spin-runtime-config = { path = "../runtime-config" }
4343
spin-telemetry = { path = "../telemetry" }
4444
terminal = { path = "../terminal" }
45-
tokio = { version = "1.23", features = ["fs"] }
45+
tokio = { version = "1.23", features = ["fs", "rt"] }
4646
tracing = { workspace = true }
4747

48+
[dev-dependencies]
49+
spin-world = { path = "../world" }
50+
tempfile = "3.12"
51+
4852
[lints]
4953
workspace = true

crates/trigger/src/cli.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod launch_metadata;
2+
mod sqlite_statements;
23
mod summary;
34

45
use std::future::Future;
@@ -13,6 +14,7 @@ use spin_common::{arg_parser::parse_kv, sloth};
1314
use spin_core::async_trait;
1415
use spin_factors_executor::{ComponentLoader, FactorsExecutor};
1516
use spin_runtime_config::{ResolvedRuntimeConfig, UserProvidedPath};
17+
use sqlite_statements::SqlStatementExecutorHook;
1618
use summary::KeyValueDefaultStoreSummaryHook;
1719

1820
use crate::factors::{TriggerFactors, TriggerFactorsRuntimeConfig};
@@ -198,6 +200,7 @@ impl<T: Trigger> FactorsTriggerCommand<T> {
198200
state_dir: self.state_dir.as_deref(),
199201
local_app_dir: local_app_dir.as_deref(),
200202
initial_key_values: self.key_values,
203+
sqlite_statements: self.sqlite_statements,
201204
allow_transient_write: self.allow_transient_write,
202205
follow_components,
203206
log_dir: self.log,
@@ -277,6 +280,8 @@ pub struct TriggerAppOptions<'a> {
277280
local_app_dir: Option<&'a str>,
278281
/// Initial key/value pairs to set in the app's default store.
279282
initial_key_values: Vec<(String, String)>,
283+
/// SQLite statements to run.
284+
sqlite_statements: Vec<String>,
280285
/// Whether to allow transient writes to mounted files
281286
allow_transient_write: bool,
282287
/// Which components should have their logs followed.
@@ -351,8 +356,6 @@ impl<T: Trigger> TriggerAppBuilder<T> {
351356
)
352357
.context("failed to create factors")?;
353358

354-
// TODO(factors): handle: self.sqlite_statements
355-
356359
// TODO: port the rest of the component loader logic
357360
struct SimpleComponentLoader;
358361

@@ -421,6 +424,7 @@ impl<T: Trigger> TriggerAppBuilder<T> {
421424
// TODO:
422425
// builder.hooks(SummariseRuntimeConfigHook::new(&self.runtime_config_file));
423426
executor.add_hooks(KeyValueDefaultStoreSummaryHook);
427+
executor.add_hooks(SqlStatementExecutorHook::new(options.sqlite_statements));
424428
// builder.hooks(SqlitePersistenceMessageHook);
425429

426430
let configured_app = {

0 commit comments

Comments
 (0)