Skip to content

Commit c15388e

Browse files
committed
Preserve SQLite streaming in native drivers
1 parent 95c2674 commit c15388e

20 files changed

Lines changed: 1164 additions & 215 deletions

Cargo.lock

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

Cargo.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,17 @@ actix-web-httpauth = "0.8.0"
5858
rand = "0.10.0"
5959
actix-multipart = "0.7.2"
6060
base64 = "0.22"
61+
bytes = "1"
6162
hmac = "0.13"
6263
sha2 = "0.11"
63-
rustls-acme = "0.15"
64+
rustls-acme = { version = "0.15", default-features = false, features = ["ring", "tls12", "webpki-roots"] }
6465
dotenvy = "0.15.7"
6566
csv-async = { version = "1.2.6", features = ["tokio"] }
66-
rustls = { version = "0.23" } # keep in sync with actix-web, awc, and rustls-acme
67+
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12", "logging"] } # keep in sync with actix-web, awc, and rustls-acme
6768
rustls-native-certs = "0.8.1"
6869
awc = { version = "3", features = ["rustls-0_23-webpki-roots"] }
6970
clap = { version = "4.5.17", features = ["derive"] }
70-
tokio-util = "0.7.12"
71+
tokio-util = { version = "0.7.12", features = ["compat"] }
7172
openidconnect = { version = "4.0.0", default-features = false, features = ["accept-rfc3339-timestamps"] }
7273
encoding_rs = "0.8.35"
7374
regex = "1"
@@ -96,7 +97,7 @@ tokio = { version = "1", features = ["rt", "time", "test-util"] }
9697

9798
[build-dependencies]
9899
awc = { version = "3", features = ["rustls-0_23-webpki-roots"] }
99-
rustls = "0.23"
100+
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12", "logging"] }
100101
actix-rt = "2.8"
101102
libflate = "2"
102103
futures-util = "0.3.21"

build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::time::Duration;
1212

1313
#[actix_rt::main]
1414
async fn main() {
15-
rustls::crypto::aws_lc_rs::default_provider()
15+
rustls::crypto::ring::default_provider()
1616
.install_default()
1717
.unwrap();
1818

src/filesystem.rs

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::webserver::ErrorWithStatus;
22
use crate::webserver::database::SupportedDatabase;
3-
use crate::webserver::{Database, StatusCodeResultExt, make_placeholder};
43
use crate::webserver::database::{DbParam, driver::DbValue};
4+
use crate::webserver::{Database, StatusCodeResultExt, make_placeholder};
55
use crate::{AppState, TEMPLATES_DIR};
66
use anyhow::Context;
77
use chrono::{DateTime, Utc};
@@ -267,9 +267,9 @@ impl DbFsQueries {
267267
log::debug!("Initializing database filesystem queries");
268268
Self::check_table_available(db).await?;
269269
Ok(Self {
270-
was_modified: Self::make_was_modified_query(db).await?,
271-
read_file: Self::make_read_file_query(db).await?,
272-
exists: Self::make_exists_query(db).await?,
270+
was_modified: Self::make_was_modified_query(db),
271+
read_file: Self::make_read_file_query(db),
272+
exists: Self::make_exists_query(db),
273273
})
274274
}
275275

@@ -284,31 +284,31 @@ impl DbFsQueries {
284284
Ok(())
285285
}
286286

287-
async fn make_was_modified_query(db: &Database) -> anyhow::Result<String> {
287+
fn make_was_modified_query(db: &Database) -> String {
288288
let was_modified_query = format!(
289289
"SELECT 1 from sqlpage_files WHERE last_modified >= {} AND path = {}",
290290
make_placeholder(db.info.kind, 1),
291291
make_placeholder(db.info.kind, 2)
292292
);
293293
log::debug!("Preparing the database filesystem was_modified_query: {was_modified_query}");
294-
Ok(was_modified_query)
294+
was_modified_query
295295
}
296296

297-
async fn make_read_file_query(db: &Database) -> anyhow::Result<String> {
297+
fn make_read_file_query(db: &Database) -> String {
298298
let read_file_query = format!(
299299
"SELECT contents from sqlpage_files WHERE path = {}",
300300
make_placeholder(db.info.kind, 1),
301301
);
302302
log::debug!("Preparing the database filesystem read_file_query: {read_file_query}");
303-
Ok(read_file_query)
303+
read_file_query
304304
}
305305

306-
async fn make_exists_query(db: &Database) -> anyhow::Result<String> {
306+
fn make_exists_query(db: &Database) -> String {
307307
let exists_query = format!(
308308
"SELECT 1 from sqlpage_files WHERE path = {}",
309309
make_placeholder(db.info.kind, 1),
310310
);
311-
Ok(exists_query)
311+
exists_query
312312
}
313313

314314
async fn file_modified_since_in_db(
@@ -351,26 +351,26 @@ impl DbFsQueries {
351351
log::debug!("Reading file {} from the database", path.display());
352352
let mut conn = app_state.db.connection.acquire().await?;
353353
conn.fetch_optional(
354-
&self.read_file,
355-
&[DbParam::Text(path.display().to_string())],
356-
)
357-
.await
358-
.map_err(anyhow::Error::from)
359-
.and_then(|row| {
360-
if let Some(row) = row {
361-
match row.values.first() {
362-
Some(DbValue::Bytes(bytes)) => Ok(bytes.clone()),
363-
Some(DbValue::Text(text)) => Ok(text.as_bytes().to_vec()),
364-
_ => Ok(Vec::new()),
365-
}
366-
} else {
367-
Err(ErrorWithStatus {
368-
status: actix_web::http::StatusCode::NOT_FOUND,
369-
}
370-
.into())
354+
&self.read_file,
355+
&[DbParam::Text(path.display().to_string())],
356+
)
357+
.await
358+
.map_err(anyhow::Error::from)
359+
.and_then(|row| {
360+
if let Some(row) = row {
361+
match row.values.first() {
362+
Some(DbValue::Bytes(bytes)) => Ok(bytes.clone()),
363+
Some(DbValue::Text(text)) => Ok(text.as_bytes().to_vec()),
364+
_ => Ok(Vec::new()),
365+
}
366+
} else {
367+
Err(ErrorWithStatus {
368+
status: actix_web::http::StatusCode::NOT_FOUND,
371369
}
372-
})
373-
.with_context(|| format!("Unable to read {} from the database", path.display()))
370+
.into())
371+
}
372+
})
373+
.with_context(|| format!("Unable to read {} from the database", path.display()))
374374
}
375375

376376
async fn file_exists(&self, app_state: &AppState, path: &Path) -> anyhow::Result<bool> {
@@ -412,9 +412,9 @@ async fn test_sql_file_read_utf8() -> anyhow::Result<()> {
412412

413413
let create_table_sql = DbFsQueries::get_create_table_sql(state.db.info.database_type);
414414
let db = &state.db;
415-
let conn = &db.connection;
416415
let mut conn = db.connection.acquire().await?;
417-
conn.execute_command("DROP TABLE IF EXISTS sqlpage_files", &[]).await?;
416+
conn.execute_command("DROP TABLE IF EXISTS sqlpage_files", &[])
417+
.await?;
418418
log::debug!("Creating table sqlpage_files: {create_table_sql}");
419419
conn.execute_command(create_table_sql, &[]).await?;
420420

@@ -425,13 +425,13 @@ async fn test_sql_file_read_utf8() -> anyhow::Result<()> {
425425
make_placeholder(dbms, 2)
426426
);
427427
conn.execute_command(
428-
&insert_sql,
429-
&[
430-
DbParam::Text("unit test file.txt".into()),
431-
DbParam::Bytes("Héllö world! 😀".as_bytes().to_vec()),
432-
],
433-
)
434-
.await?;
428+
&insert_sql,
429+
&[
430+
DbParam::Text("unit test file.txt".into()),
431+
DbParam::Bytes("Héllö world! 😀".as_bytes().to_vec()),
432+
],
433+
)
434+
.await?;
435435

436436
let fs = FileSystem::init("/", db).await;
437437
let actual = fs

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
//! When processing a request, `SQLPage`:
3838
//!
3939
//! 1. Parses the SQL using sqlparser-rs. Once a SQL file is parsed, it is cached for later reuse.
40-
//! 2. Executes queries through sqlx.
40+
//! 2. Executes queries through native database drivers.
4141
//! 3. Finds the requested component's handlebars template in the database or in the filesystem.
4242
//! 4. Maps results to the component template, using handlebars-rs.
4343
//! 5. Streams rendered HTML to the client.

src/telemetry_metrics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
use crate::webserver::database::DbPool;
12
use opentelemetry::global;
23
use opentelemetry::metrics::{Histogram, ObservableGauge};
34
use opentelemetry_semantic_conventions::attribute as otel;
45
use opentelemetry_semantic_conventions::metric as otel_metric;
5-
use crate::webserver::database::DbPool;
66

77
pub struct TelemetryMetrics {
88
pub http_request_duration: Histogram<f64>,

src/webserver/database/connect.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ impl Database {
2323
}
2424
log::debug!("Connecting to a {db_kind:?} database on {database_url}");
2525
let on_connect_sql = read_connection_handler(config, ON_CONNECT_FILE);
26-
let _on_reset_sql = read_connection_handler(config, ON_RESET_FILE);
27-
if _on_reset_sql.is_some() {
26+
let on_reset_sql = read_connection_handler(config, ON_RESET_FILE);
27+
if on_reset_sql.is_some() {
2828
log::warn!(
2929
"{ON_RESET_FILE} is currently ignored by the native driver pool because connections are not reused yet"
3030
);
@@ -111,7 +111,10 @@ fn read_connection_handler(config: &AppConfig, file_name: &str) -> Option<String
111111
);
112112
return None;
113113
}
114-
log::info!("Creating a custom SQL connection handler from {}", file.display());
114+
log::info!(
115+
"Creating a custom SQL connection handler from {}",
116+
file.display()
117+
);
115118
match std::fs::read_to_string(&file) {
116119
Ok(sql) => {
117120
log::trace!("The custom SQL connection handler is:\n{sql}");

src/webserver/database/csv_import.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,9 @@ async fn test_end_to_end() {
324324
uploaded_file: "my_file.csv".into(),
325325
}
326326
);
327-
let db = crate::webserver::Database::init(&test_config()).await.unwrap();
327+
let db = crate::webserver::Database::init(&test_config())
328+
.await
329+
.unwrap();
328330
let mut conn = db.connection.acquire().await.unwrap();
329331
conn.execute_command("CREATE TABLE my_table (col1 TEXT, col2 TEXT)", &[])
330332
.await
@@ -339,8 +341,14 @@ async fn test_end_to_end() {
339341
.into_iter()
340342
.filter_map(|item| match item {
341343
super::driver::DbStatementResult::Row(row) => Some((
342-
match &row.values[0] { super::driver::DbValue::Text(s) => s.clone(), other => format!("{other:?}") },
343-
match &row.values[1] { super::driver::DbValue::Text(s) => s.clone(), other => format!("{other:?}") },
344+
match &row.values[0] {
345+
super::driver::DbValue::Text(s) => s.clone(),
346+
other => format!("{other:?}"),
347+
},
348+
match &row.values[1] {
349+
super::driver::DbValue::Text(s) => s.clone(),
350+
other => format!("{other:?}"),
351+
},
344352
)),
345353
super::driver::DbStatementResult::Finished => None,
346354
})

0 commit comments

Comments
 (0)