diff --git a/Cargo.lock b/Cargo.lock index 1e3d5a3d..2eb87fc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2559,6 +2559,7 @@ dependencies = [ "tokio", "tokio-stream", "tokio-util", + "toml 0.7.6", "tracing", "tracing-subscriber", "turmoil", @@ -3932,6 +3933,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -4124,7 +4134,6 @@ version = "0.15.0" dependencies = [ "anyhow", "arbitrary", - "async-bincode", "async-lock", "async-trait", "aws-config", @@ -4175,14 +4184,12 @@ dependencies = [ "tokio", "tokio-stream", "tokio-tungstenite", - "tokio-util", "tonic 0.8.3", "tonic-build", "tower", "tower-http", "tracing", "tracing-subscriber", - "turmoil", "url", "uuid", "vergen", @@ -4579,6 +4586,40 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" +dependencies = [ + "indexmap 2.0.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tonic" version = "0.8.3" @@ -5226,7 +5267,7 @@ dependencies = [ "rustix 0.37.23", "serde", "sha2", - "toml", + "toml 0.5.11", "windows-sys 0.48.0", "zstd", ] @@ -5716,6 +5757,15 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "winnow" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a2094c43cc94775293eaa0e499fbc30048a6d824ac82c0351a8c0bf9112529" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.10.1" diff --git a/libsqlx-server/Cargo.toml b/libsqlx-server/Cargo.toml index b4f9d366..6393f6cb 100644 --- a/libsqlx-server/Cargo.toml +++ b/libsqlx-server/Cargo.toml @@ -31,6 +31,7 @@ thiserror = "1.0.43" tokio = { version = "1.29.1", features = ["full"] } tokio-stream = "0.1.14" tokio-util = "0.7.8" +toml = "0.7.6" tracing = "0.1.37" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } uuid = { version = "1.4.0", features = ["v4"] } diff --git a/libsqlx-server/src/allocation/mod.rs b/libsqlx-server/src/allocation/mod.rs index a086f479..b0393165 100644 --- a/libsqlx-server/src/allocation/mod.rs +++ b/libsqlx-server/src/allocation/mod.rs @@ -27,7 +27,7 @@ pub enum AllocationMessage { HranaPipelineReq { req: PipelineRequestBody, ret: oneshot::Sender>, - } + }, } pub enum Database { @@ -87,8 +87,9 @@ pub struct ConnectionHandle { impl ConnectionHandle { pub async fn exec(&self, f: F) -> crate::Result - where F: for<'a> FnOnce(&'a mut (dyn libsqlx::Connection + 'a)) -> R + Send + 'static, - R: Send + 'static, + where + F: for<'a> FnOnce(&'a mut (dyn libsqlx::Connection + 'a)) -> R + Send + 'static, + R: Send + 'static, { let (sender, ret) = oneshot::channel(); let cb = move |conn: &mut dyn libsqlx::Connection| { @@ -154,7 +155,6 @@ impl Allocation { exec: exec_sender, exit: close_sender, } - } fn next_conn_id(&mut self) -> u32 { diff --git a/libsqlx-server/src/config.rs b/libsqlx-server/src/config.rs new file mode 100644 index 00000000..4772b53f --- /dev/null +++ b/libsqlx-server/src/config.rs @@ -0,0 +1,98 @@ +use std::net::SocketAddr; +use std::path::PathBuf; + +use serde::Deserialize; +use serde::de::Visitor; + +#[derive(Deserialize, Debug, Clone)] +pub struct Config { + /// Database path + #[serde(default = "default_db_path")] + pub db_path: PathBuf, + /// Cluster configuration + pub cluster: ClusterConfig, + /// User API configuration + pub user_api: UserApiConfig, + /// Admin API configuration + pub admin_api: AdminApiConfig, +} + +impl Config { + pub fn validate(&self) -> color_eyre::Result<()> { + // TODO: implement validation + Ok(()) + } +} + +#[derive(Deserialize, Debug, Clone)] +pub struct ClusterConfig { + /// Address to bind this node to + #[serde(default = "default_linc_addr")] + pub addr: SocketAddr, + /// List of peers in the format `:` + pub peers: Vec, +} + +#[derive(Deserialize, Debug, Clone)] +pub struct UserApiConfig { + #[serde(default = "default_user_addr")] + pub addr: SocketAddr, +} + +#[derive(Deserialize, Debug, Clone)] +pub struct AdminApiConfig { + #[serde(default = "default_admin_addr")] + pub addr: SocketAddr, +} + +fn default_db_path() -> PathBuf { + PathBuf::from("data.sqld") +} + +fn default_admin_addr() -> SocketAddr { + "0.0.0.0:8081".parse().unwrap() +} + +fn default_user_addr() -> SocketAddr { + "0.0.0.0:8080".parse().unwrap() +} + +fn default_linc_addr() -> SocketAddr { + "0.0.0.0:5001".parse().unwrap() +} + +#[derive(Debug, Clone)] +struct Peer { + id: u64, + addr: String, +} + +impl<'de> Deserialize<'de> for Peer { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de> { + struct V; + + impl Visitor<'_> for V { + type Value = Peer; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a string in the format :") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, { + + let mut iter = v.split(":"); + let Some(id) = iter.next() else { return Err(E::custom("node id is missing")) }; + let Ok(id) = id.parse::() else { return Err(E::custom("failed to parse node id")) }; + let Some(addr) = iter.next() else { return Err(E::custom("node address is missing")) }; + Ok(Peer { id, addr: addr.to_string() }) + } + } + + deserializer.deserialize_str(V) + } +} + diff --git a/libsqlx-server/src/database.rs b/libsqlx-server/src/database.rs index e4971b74..4945cd70 100644 --- a/libsqlx-server/src/database.rs +++ b/libsqlx-server/src/database.rs @@ -1,16 +1,22 @@ use tokio::sync::{mpsc, oneshot}; -use crate::hrana::http::proto::{PipelineRequestBody, PipelineResponseBody}; use crate::allocation::AllocationMessage; +use crate::hrana::http::proto::{PipelineRequestBody, PipelineResponseBody}; pub struct Database { pub sender: mpsc::Sender, } impl Database { - pub async fn hrana_pipeline(&self, req: PipelineRequestBody) -> crate::Result { + pub async fn hrana_pipeline( + &self, + req: PipelineRequestBody, + ) -> crate::Result { let (sender, ret) = oneshot::channel(); - self.sender.send(AllocationMessage::HranaPipelineReq { req, ret: sender }).await.unwrap(); + self.sender + .send(AllocationMessage::HranaPipelineReq { req, ret: sender }) + .await + .unwrap(); ret.await.unwrap() } } diff --git a/libsqlx-server/src/hrana/batch.rs b/libsqlx-server/src/hrana/batch.rs index 7d2a1f0c..1368991e 100644 --- a/libsqlx-server/src/hrana/batch.rs +++ b/libsqlx-server/src/hrana/batch.rs @@ -10,7 +10,7 @@ use super::{proto, ProtocolError, Version}; use color_eyre::eyre::anyhow; use libsqlx::analysis::Statement; use libsqlx::program::{Cond, Program, Step}; -use libsqlx::query::{Query, Params}; +use libsqlx::query::{Params, Query}; use libsqlx::result_builder::{StepResult, StepResultsBuilder}; fn proto_cond_to_cond(cond: &proto::BatchCond, max_step_i: usize) -> color_eyre::Result { @@ -73,11 +73,13 @@ pub async fn execute_batch( db: &ConnectionHandle, pgm: Program, ) -> color_eyre::Result { - let builder = db.exec(move |conn| -> color_eyre::Result<_> { - let mut builder = HranaBatchProtoBuilder::default(); - conn.execute_program(pgm, &mut builder)?; - Ok(builder) - }).await??; + let builder = db + .exec(move |conn| -> color_eyre::Result<_> { + let mut builder = HranaBatchProtoBuilder::default(); + conn.execute_program(pgm, &mut builder)?; + Ok(builder) + }) + .await??; Ok(builder.into_ret()) } @@ -104,18 +106,18 @@ pub fn proto_sequence_to_program(sql: &str) -> color_eyre::Result { }) .collect(); - Ok(Program { - steps, - }) + Ok(Program { steps }) } pub async fn execute_sequence(conn: &ConnectionHandle, pgm: Program) -> color_eyre::Result<()> { - let builder = conn.exec(move |conn| -> color_eyre::Result<_> { - let mut builder = StepResultsBuilder::default(); - conn.execute_program(pgm, &mut builder)?; + let builder = conn + .exec(move |conn| -> color_eyre::Result<_> { + let mut builder = StepResultsBuilder::default(); + conn.execute_program(pgm, &mut builder)?; - Ok(builder) - }).await??; + Ok(builder) + }) + .await??; builder .into_ret() diff --git a/libsqlx-server/src/hrana/http/mod.rs b/libsqlx-server/src/hrana/http/mod.rs index 5e22bedc..651ab3f0 100644 --- a/libsqlx-server/src/hrana/http/mod.rs +++ b/libsqlx-server/src/hrana/http/mod.rs @@ -49,10 +49,11 @@ fn handle_index() -> color_eyre::Result> { pub async fn handle_pipeline( server: &Server, req: PipelineRequestBody, - mk_conn: F + mk_conn: F, ) -> color_eyre::Result -where F: FnOnce() -> Fut, - Fut: Future>, +where + F: FnOnce() -> Fut, + Fut: Future>, { let mut stream_guard = stream::acquire(server, req.baton.as_deref(), mk_conn).await?; @@ -73,7 +74,9 @@ where F: FnOnce() -> Fut, Ok(resp_body) } -async fn read_request_json(req: hyper::Request) -> color_eyre::Result { +async fn read_request_json( + req: hyper::Request, +) -> color_eyre::Result { let req_body = hyper::body::to_bytes(req.into_body()) .await .context("Could not read request body")?; diff --git a/libsqlx-server/src/hrana/http/stream.rs b/libsqlx-server/src/hrana/http/stream.rs index 1261e7c2..5f40537e 100644 --- a/libsqlx-server/src/hrana/http/stream.rs +++ b/libsqlx-server/src/hrana/http/stream.rs @@ -106,8 +106,9 @@ pub async fn acquire<'srv, F, Fut>( baton: Option<&str>, mk_conn: F, ) -> color_eyre::Result> -where F: FnOnce() -> Fut, - Fut: Future>, +where + F: FnOnce() -> Fut, + Fut: Future>, { let stream = match baton { Some(baton) => { @@ -117,7 +118,10 @@ where F: FnOnce() -> Fut, let handle = state.handles.get_mut(&stream_id); match handle { None => { - return Err(ProtocolError::BatonInvalid(format!("Stream handle for {stream_id} was not found")).into()) + return Err(ProtocolError::BatonInvalid(format!( + "Stream handle for {stream_id} was not found" + )) + .into()) } Some(Handle::Acquired) => { return Err(ProtocolError::BatonReused) @@ -149,7 +153,9 @@ where F: FnOnce() -> Fut, stream } None => { - let conn = mk_conn().await.context("Could not create a database connection")?; + let conn = mk_conn() + .await + .context("Could not create a database connection")?; let mut state = server.stream_state.lock(); let stream = Box::new(Stream { @@ -291,7 +297,8 @@ fn decode_baton(server: &Server, baton_str: &str) -> color_eyre::Result<(u64, u6 return Err(ProtocolError::BatonInvalid(format!( "Baton has invalid size of {} bytes", baton_data.len() - )).into()); + )) + .into()); } let payload = &baton_data[0..16]; @@ -299,8 +306,11 @@ fn decode_baton(server: &Server, baton_str: &str) -> color_eyre::Result<(u64, u6 let mut hmac = hmac::Hmac::::new_from_slice(&server.baton_key).unwrap(); hmac.update(payload); - hmac.verify_slice(received_mac) - .map_err(|_| anyhow!(ProtocolError::BatonInvalid("Invalid MAC on baton".to_string())))?; + hmac.verify_slice(received_mac).map_err(|_| { + anyhow!(ProtocolError::BatonInvalid( + "Invalid MAC on baton".to_string() + )) + })?; let stream_id = u64::from_be_bytes(payload[0..8].try_into().unwrap()); let baton_seq = u64::from_be_bytes(payload[8..16].try_into().unwrap()); diff --git a/libsqlx-server/src/hrana/result_builder.rs b/libsqlx-server/src/hrana/result_builder.rs index 94b23775..b6b8c635 100644 --- a/libsqlx-server/src/hrana/result_builder.rs +++ b/libsqlx-server/src/hrana/result_builder.rs @@ -194,10 +194,10 @@ impl ResultBuilder for SingleStatementBuilder { } fn finish( - &mut self, + &mut self, _is_txn: bool, _frame_no: Option, - ) -> Result<(), QueryResultBuilderError> { + ) -> Result<(), QueryResultBuilderError> { Ok(()) } } diff --git a/libsqlx-server/src/hrana/stmt.rs b/libsqlx-server/src/hrana/stmt.rs index e74c3d42..5453ab5c 100644 --- a/libsqlx-server/src/hrana/stmt.rs +++ b/libsqlx-server/src/hrana/stmt.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; -use color_eyre::eyre::{bail, anyhow}; +use color_eyre::eyre::{anyhow, bail}; use libsqlx::analysis::Statement; -use libsqlx::query::{Query, Params, Value}; +use libsqlx::query::{Params, Query, Value}; use super::result_builder::SingleStatementBuilder; use super::{proto, ProtocolError, Version}; @@ -47,14 +47,15 @@ pub async fn execute_stmt( conn: &ConnectionHandle, query: Query, ) -> color_eyre::Result { - let builder = conn.exec(move |conn| -> color_eyre::Result<_> { - let mut builder = SingleStatementBuilder::default(); - let pgm = libsqlx::program::Program::from_queries(std::iter::once(query)); - conn.execute_program(pgm, &mut builder)?; + let builder = conn + .exec(move |conn| -> color_eyre::Result<_> { + let mut builder = SingleStatementBuilder::default(); + let pgm = libsqlx::program::Program::from_queries(std::iter::once(query)); + conn.execute_program(pgm, &mut builder)?; - Ok(builder) - - }).await??; + Ok(builder) + }) + .await??; builder .into_ret() @@ -191,21 +192,27 @@ fn proto_value_from_value(value: Value) -> proto::Value { // } // } -pub fn stmt_error_from_sqld_error(sqld_error: libsqlx::error::Error) -> Result { +pub fn stmt_error_from_sqld_error( + sqld_error: libsqlx::error::Error, +) -> Result { Ok(match sqld_error { libsqlx::error::Error::LibSqlInvalidQueryParams(msg) => StmtError::ArgsInvalid { msg }, libsqlx::error::Error::LibSqlTxTimeout => StmtError::TransactionTimeout, libsqlx::error::Error::LibSqlTxBusy => StmtError::TransactionBusy, libsqlx::error::Error::Blocked(reason) => StmtError::Blocked { reason }, libsqlx::error::Error::RusqliteError(rusqlite_error) => match rusqlite_error { - libsqlx::error::RusqliteError::SqliteFailure(sqlite_error, Some(message)) => StmtError::SqliteError { - source: sqlite_error, - message, - }, - libsqlx::error::RusqliteError::SqliteFailure(sqlite_error, None) => StmtError::SqliteError { - message: sqlite_error.to_string(), - source: sqlite_error, - }, + libsqlx::error::RusqliteError::SqliteFailure(sqlite_error, Some(message)) => { + StmtError::SqliteError { + source: sqlite_error, + message, + } + } + libsqlx::error::RusqliteError::SqliteFailure(sqlite_error, None) => { + StmtError::SqliteError { + message: sqlite_error.to_string(), + source: sqlite_error, + } + } libsqlx::error::RusqliteError::SqlInputError { error: sqlite_error, msg: message, diff --git a/libsqlx-server/src/http/admin.rs b/libsqlx-server/src/http/admin.rs index 6b23ef58..346987c4 100644 --- a/libsqlx-server/src/http/admin.rs +++ b/libsqlx-server/src/http/admin.rs @@ -11,7 +11,7 @@ use crate::{ meta::Store, }; -pub struct AdminApiConfig { +pub struct Config { pub meta_store: Arc, } @@ -19,7 +19,7 @@ struct AdminServerState { meta_store: Arc, } -pub async fn run_admin_api(config: AdminApiConfig, listener: I) -> Result<()> +pub async fn run_admin_api(config: Config, listener: I) -> Result<()> where I: Accept, I::Conn: AsyncRead + AsyncWrite + Send + Unpin + 'static, diff --git a/libsqlx-server/src/http/user/mod.rs b/libsqlx-server/src/http/user/mod.rs index 4c314a39..bc3265e9 100644 --- a/libsqlx-server/src/http/user/mod.rs +++ b/libsqlx-server/src/http/user/mod.rs @@ -13,7 +13,7 @@ use crate::manager::Manager; mod error; mod extractors; -pub struct UserApiConfig { +pub struct Config { pub manager: Arc, } @@ -21,7 +21,7 @@ struct UserApiState { manager: Arc, } -pub async fn run_user_api(config: UserApiConfig, listener: I) -> Result<()> +pub async fn run_user_api(config: Config, listener: I) -> Result<()> where I: Accept, I::Conn: AsyncRead + AsyncWrite + Send + Unpin + 'static, @@ -41,7 +41,10 @@ where Ok(()) } -async fn handle_hrana_pipeline(db: Database, Json(req): Json) -> Json { +async fn handle_hrana_pipeline( + db: Database, + Json(req): Json, +) -> Json { let resp = db.hrana_pipeline(req).await; dbg!(); Json(resp.unwrap()) diff --git a/libsqlx-server/src/linc/bus.rs b/libsqlx-server/src/linc/bus.rs index 6fcc3238..f9533347 100644 --- a/libsqlx-server/src/linc/bus.rs +++ b/libsqlx-server/src/linc/bus.rs @@ -1,7 +1,7 @@ use std::collections::{hash_map::Entry, HashMap}; use std::sync::Arc; -use color_eyre::eyre::{bail, anyhow}; +use color_eyre::eyre::{anyhow, bail}; use parking_lot::Mutex; use tokio::sync::{mpsc, Notify}; use uuid::Uuid; diff --git a/libsqlx-server/src/linc/connection.rs b/libsqlx-server/src/linc/connection.rs index b5a8ce25..1d598cef 100644 --- a/libsqlx-server/src/linc/connection.rs +++ b/libsqlx-server/src/linc/connection.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use async_bincode::tokio::AsyncBincodeStream; use async_bincode::AsyncDestination; -use color_eyre::eyre::{bail, anyhow}; +use color_eyre::eyre::{anyhow, bail}; use futures::{SinkExt, StreamExt}; use tokio::io::{AsyncRead, AsyncWrite}; use tokio::sync::mpsc::error::TrySendError; diff --git a/libsqlx-server/src/main.rs b/libsqlx-server/src/main.rs index 16e6a38e..cab52d5d 100644 --- a/libsqlx-server/src/main.rs +++ b/libsqlx-server/src/main.rs @@ -1,10 +1,12 @@ -use std::{path::PathBuf, sync::Arc}; +use std::fs::read_to_string; +use std::path::PathBuf; +use std::sync::Arc; +use clap::Parser; use color_eyre::eyre::Result; -use http::{ - admin::{run_admin_api, AdminApiConfig}, - user::{run_user_api, UserApiConfig}, -}; +use config::{AdminApiConfig, UserApiConfig}; +use http::admin::run_admin_api; +use http::user::run_user_api; use hyper::server::conn::AddrIncoming; use manager::Manager; use meta::Store; @@ -13,34 +15,65 @@ use tracing::metadata::LevelFilter; use tracing_subscriber::prelude::*; mod allocation; +mod config; mod database; mod hrana; mod http; +mod linc; mod manager; mod meta; -mod linc; + +#[derive(Debug, Parser)] +struct Args { + /// Path to the node configuration file + #[clap(long, short)] + config: PathBuf, +} + +async fn spawn_admin_api( + set: &mut JoinSet>, + config: &AdminApiConfig, + meta_store: Arc, +) -> Result<()> { + let admin_api_listener = tokio::net::TcpListener::bind(config.addr).await?; + let fut = run_admin_api( + http::admin::Config { meta_store }, + AddrIncoming::from_listener(admin_api_listener)?, + ); + set.spawn(fut); + + Ok(()) +} + +async fn spawn_user_api( + set: &mut JoinSet>, + config: &UserApiConfig, + manager: Arc, +) -> Result<()> { + let user_api_listener = tokio::net::TcpListener::bind(config.addr).await?; + set.spawn(run_user_api( + http::user::Config { manager }, + AddrIncoming::from_listener(user_api_listener)?, + )); + + Ok(()) +} #[tokio::main] async fn main() -> Result<()> { init(); + let args = Args::parse(); + let config_str = read_to_string(args.config)?; + let config: config::Config = toml::from_str(&config_str)?; + config.validate()?; + let mut join_set = JoinSet::new(); - let db_path = PathBuf::from("database"); - let store = Arc::new(Store::new(&db_path)); - let admin_api_listener = tokio::net::TcpListener::bind("0.0.0.0:3456").await?; - join_set.spawn(run_admin_api( - AdminApiConfig { - meta_store: store.clone(), - }, - AddrIncoming::from_listener(admin_api_listener)?, - )); + let store = Arc::new(Store::new(&config.db_path)); + let manager = Arc::new(Manager::new(config.db_path.clone(), store.clone(), 100)); - let manager = Arc::new(Manager::new(db_path.clone(), store, 100)); - let user_api_listener = tokio::net::TcpListener::bind("0.0.0.0:3457").await?; - join_set.spawn(run_user_api( - UserApiConfig { manager }, - AddrIncoming::from_listener(user_api_listener)?, - )); + spawn_admin_api(&mut join_set, &config.admin_api_config, store.clone()).await?; + spawn_user_api(&mut join_set, &config.user_api_config, manager).await?; join_set.join_next().await; diff --git a/libsqlx/src/analysis.rs b/libsqlx/src/analysis.rs index fccbf3dc..97ef5f5b 100644 --- a/libsqlx/src/analysis.rs +++ b/libsqlx/src/analysis.rs @@ -258,7 +258,7 @@ impl Statement { found: Some(found), }, Some((line, col)), - )) => Some(Err(crate::error::Error::SyntaxError { line, col, found})), + )) => Some(Err(crate::error::Error::SyntaxError { line, col, found })), Err(e) => Some(Err(e.into())), } }) diff --git a/libsqlx/src/connection.rs b/libsqlx/src/connection.rs index 38d31964..e2fd05f8 100644 --- a/libsqlx/src/connection.rs +++ b/libsqlx/src/connection.rs @@ -2,7 +2,7 @@ use rusqlite::types::Value; use crate::program::{Program, Step}; use crate::query::Query; -use crate::result_builder::{ResultBuilder, QueryBuilderConfig, QueryResultBuilderError}; +use crate::result_builder::{QueryBuilderConfig, QueryResultBuilderError, ResultBuilder}; #[derive(Debug, Clone)] pub struct DescribeResponse { diff --git a/libsqlx/src/database/libsql/connection.rs b/libsqlx/src/database/libsql/connection.rs index 554a22da..cd5bcff3 100644 --- a/libsqlx/src/database/libsql/connection.rs +++ b/libsqlx/src/database/libsql/connection.rs @@ -177,7 +177,7 @@ impl LibsqlConnection { query .params .bind(&mut stmt) - .map_err(|e|Error::LibSqlInvalidQueryParams(e.to_string()))?; + .map_err(|e| Error::LibSqlInvalidQueryParams(e.to_string()))?; let mut qresult = stmt.raw_query(); builder.begin_rows()?; diff --git a/libsqlx/src/error.rs b/libsqlx/src/error.rs index 47fde1ae..07a71831 100644 --- a/libsqlx/src/error.rs +++ b/libsqlx/src/error.rs @@ -1,6 +1,6 @@ use crate::result_builder::QueryResultBuilderError; -pub use rusqlite::Error as RusqliteError; pub use rusqlite::ffi::ErrorCode; +pub use rusqlite::Error as RusqliteError; #[allow(clippy::enum_variant_names)] #[derive(Debug, thiserror::Error)] @@ -39,10 +39,12 @@ pub enum Error { UnsupportedStatement, #[error("Syntax error at {line}:{col}: {found}")] SyntaxError { - line: u64, col: usize, found: String + line: u64, + col: usize, + found: String, }, #[error(transparent)] - LexerError(#[from] sqlite3_parser::lexer::sql::Error) + LexerError(#[from] sqlite3_parser::lexer::sql::Error), } impl From for Error { diff --git a/libsqlx/src/lib.rs b/libsqlx/src/lib.rs index f9ef106d..a89c2771 100644 --- a/libsqlx/src/lib.rs +++ b/libsqlx/src/lib.rs @@ -12,8 +12,8 @@ pub type Result = std::result::Result; pub use connection::Connection; pub use database::libsql; +pub use database::libsql::replication_log::FrameNo; pub use database::proxy; pub use database::Database; -pub use database::libsql::replication_log::FrameNo; pub use rusqlite; diff --git a/libsqlx/src/program.rs b/libsqlx/src/program.rs index 131dd125..0b5c7980 100644 --- a/libsqlx/src/program.rs +++ b/libsqlx/src/program.rs @@ -25,14 +25,16 @@ impl Program { /// transforms a collection of queries into a batch program. The execution of each query /// depends on the success of the previous one. pub fn from_queries(qs: impl IntoIterator) -> Self { - let steps = qs.into_iter().enumerate().map(|(idx, query)| Step { - cond: (idx > 0).then(|| Cond::Ok { step: idx - 1 }), - query, - }) - .collect(); + let steps = qs + .into_iter() + .enumerate() + .map(|(idx, query)| Step { + cond: (idx > 0).then(|| Cond::Ok { step: idx - 1 }), + query, + }) + .collect(); Self { steps } - } #[cfg(test)]