From 5d042e35b1e7e77930ffd996afecf11a154c30a5 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Wed, 11 Mar 2020 09:21:15 -0700 Subject: [PATCH] sqlite: stub --- Cargo.toml | 1 + sqlx-core/Cargo.toml | 1 + sqlx-core/src/encode.rs | 12 +++---- sqlx-core/src/lib.rs | 10 +++++- sqlx-core/src/sqlite/arguments.rs | 37 +++++++++++++++++++++ sqlx-core/src/sqlite/connection.rs | 31 +++++++++++++++++ sqlx-core/src/sqlite/cursor.rs | 40 ++++++++++++++++++++++ sqlx-core/src/sqlite/database.rs | 35 ++++++++++++++++++++ sqlx-core/src/sqlite/error.rs | 11 +++++++ sqlx-core/src/sqlite/executor.rs | 53 ++++++++++++++++++++++++++++++ sqlx-core/src/sqlite/mod.rs | 16 +++++++++ sqlx-core/src/sqlite/row.rs | 38 +++++++++++++++++++++ sqlx-core/src/sqlite/types/mod.rs | 18 ++++++++++ sqlx-macros/Cargo.toml | 1 + 14 files changed, 297 insertions(+), 7 deletions(-) create mode 100644 sqlx-core/src/sqlite/arguments.rs create mode 100644 sqlx-core/src/sqlite/connection.rs create mode 100644 sqlx-core/src/sqlite/cursor.rs create mode 100644 sqlx-core/src/sqlite/database.rs create mode 100644 sqlx-core/src/sqlite/error.rs create mode 100644 sqlx-core/src/sqlite/executor.rs create mode 100644 sqlx-core/src/sqlite/mod.rs create mode 100644 sqlx-core/src/sqlite/row.rs create mode 100644 sqlx-core/src/sqlite/types/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 5f14e354..facc6367 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ runtime-tokio = [ "sqlx-core/runtime-tokio", "sqlx-macros/runtime-tokio" ] # database postgres = [ "sqlx-core/postgres", "sqlx-macros/postgres" ] mysql = [ "sqlx-core/mysql", "sqlx-macros/mysql" ] +sqlite = [ "sqlx-core/sqlite", "sqlx-macros/sqlite" ] # types chrono = [ "sqlx-core/chrono", "sqlx-macros/chrono" ] diff --git a/sqlx-core/Cargo.toml b/sqlx-core/Cargo.toml index cd36977b..61859103 100644 --- a/sqlx-core/Cargo.toml +++ b/sqlx-core/Cargo.toml @@ -17,6 +17,7 @@ default = [ "runtime-async-std" ] unstable = [] postgres = [ "md-5", "sha2", "base64", "sha-1", "rand", "hmac" ] mysql = [ "sha-1", "sha2", "generic-array", "num-bigint", "base64", "digest", "rand" ] +sqlite = [ ] tls = [ "async-native-tls" ] runtime-async-std = [ "async-native-tls/runtime-async-std", "async-std" ] runtime-tokio = [ "async-native-tls/runtime-tokio", "tokio" ] diff --git a/sqlx-core/src/encode.rs b/sqlx-core/src/encode.rs index 3f856dfd..1fc2f104 100644 --- a/sqlx-core/src/encode.rs +++ b/sqlx-core/src/encode.rs @@ -21,9 +21,9 @@ where DB: Database + ?Sized, { /// Writes the value of `self` into `buf` in the expected format for the database. - fn encode(&self, buf: &mut Vec); + fn encode(&self, buf: &mut DB::RawBuffer); - fn encode_nullable(&self, buf: &mut Vec) -> IsNull { + fn encode_nullable(&self, buf: &mut DB::RawBuffer) -> IsNull { self.encode(buf); IsNull::No @@ -40,11 +40,11 @@ where T: Type, T: Encode, { - fn encode(&self, buf: &mut Vec) { + fn encode(&self, buf: &mut DB::RawBuffer) { (*self).encode(buf) } - fn encode_nullable(&self, buf: &mut Vec) -> IsNull { + fn encode_nullable(&self, buf: &mut DB::RawBuffer) -> IsNull { (*self).encode_nullable(buf) } @@ -59,12 +59,12 @@ where T: Type, T: Encode, { - fn encode(&self, buf: &mut Vec) { + fn encode(&self, buf: &mut DB::RawBuffer) { // Forward to [encode_nullable] and ignore the result let _ = self.encode_nullable(buf); } - fn encode_nullable(&self, buf: &mut Vec) -> IsNull { + fn encode_nullable(&self, buf: &mut DB::RawBuffer) -> IsNull { if let Some(self_) = self { self_.encode(buf); diff --git a/sqlx-core/src/lib.rs b/sqlx-core/src/lib.rs index 381a0ce7..d8351e9d 100644 --- a/sqlx-core/src/lib.rs +++ b/sqlx-core/src/lib.rs @@ -1,6 +1,10 @@ //! Core of SQLx, the rust SQL toolkit. Not intended to be used directly. -#![forbid(unsafe_code)] +// When compiling with support for SQLite we must allow some unsafe code in order to +// interface with the inherently unsafe C module. This unsafe code is contained +// to the sqlite module. +#![cfg_attr(feature = "sqlite", deny(unsafe_code))] +#![cfg_attr(not(feature = "sqlite"), forbid(unsafe_code))] #![recursion_limit = "512"] #![cfg_attr(docsrs, feature(doc_cfg))] @@ -48,6 +52,10 @@ pub mod mysql; #[cfg_attr(docsrs, doc(cfg(feature = "postgres")))] pub mod postgres; +#[cfg(feature = "sqlite")] +#[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))] +pub mod sqlite; + pub use error::{Error, Result}; // Named Lifetimes: diff --git a/sqlx-core/src/sqlite/arguments.rs b/sqlx-core/src/sqlite/arguments.rs new file mode 100644 index 00000000..2fb4da38 --- /dev/null +++ b/sqlx-core/src/sqlite/arguments.rs @@ -0,0 +1,37 @@ +use crate::arguments::Arguments; +use crate::encode::Encode; +use crate::sqlite::Sqlite; +use crate::types::Type; + +#[derive(Debug, Clone)] +pub enum SqliteValue { + // TODO: Take by reference to remove the allocation + Text(String), + + // TODO: Take by reference to remove the allocation + Blob(Vec), + + Double(f64), + + Int(i64), +} + +#[derive(Default)] +pub struct SqliteArguments { + values: Vec, +} + +impl Arguments for SqliteArguments { + type Database = Sqlite; + + fn reserve(&mut self, len: usize, _size_hint: usize) { + self.values.reserve(1); + } + + fn add(&mut self, value: T) + where + T: Encode + Type, + { + value.encode(&mut self.values); + } +} diff --git a/sqlx-core/src/sqlite/connection.rs b/sqlx-core/src/sqlite/connection.rs new file mode 100644 index 00000000..ca5e528c --- /dev/null +++ b/sqlx-core/src/sqlite/connection.rs @@ -0,0 +1,31 @@ +use std::convert::TryInto; + +use futures_core::future::BoxFuture; + +use crate::connection::{Connect, Connection}; +use crate::url::Url; + +pub struct SqliteConnection {} + +impl Connect for SqliteConnection { + fn connect(url: T) -> BoxFuture<'static, crate::Result> + where + T: TryInto, + Self: Sized, + { + // Box::pin(SqliteConnection::new(url.try_into())) + todo!() + } +} + +impl Connection for SqliteConnection { + fn close(self) -> BoxFuture<'static, crate::Result<()>> { + // Box::pin(terminate(self.stream)) + todo!() + } + + fn ping(&mut self) -> BoxFuture> { + //Box::pin(Executor::execute(self, "SELECT 1").map_ok(|_| ())) + todo!() + } +} diff --git a/sqlx-core/src/sqlite/cursor.rs b/sqlx-core/src/sqlite/cursor.rs new file mode 100644 index 00000000..d2ad0b00 --- /dev/null +++ b/sqlx-core/src/sqlite/cursor.rs @@ -0,0 +1,40 @@ +use futures_core::future::BoxFuture; + +use crate::connection::MaybeOwnedConnection; +use crate::cursor::Cursor; +use crate::executor::Execute; +use crate::pool::Pool; +use crate::sqlite::connection::SqliteConnection; +use crate::sqlite::{Sqlite, SqliteRow}; + +pub struct SqliteCursor<'c, 'q> { + c: std::marker::PhantomData<&'c ()>, + q: std::marker::PhantomData<&'q ()>, +} + +impl<'c, 'q> Cursor<'c, 'q> for SqliteCursor<'c, 'q> { + type Database = Sqlite; + + #[doc(hidden)] + fn from_pool(pool: &Pool, query: E) -> Self + where + Self: Sized, + E: Execute<'q, Sqlite>, + { + todo!() + } + + #[doc(hidden)] + fn from_connection(conn: C, query: E) -> Self + where + Self: Sized, + C: Into>, + E: Execute<'q, Sqlite>, + { + todo!() + } + + fn next(&mut self) -> BoxFuture>>> { + todo!() + } +} diff --git a/sqlx-core/src/sqlite/database.rs b/sqlx-core/src/sqlite/database.rs new file mode 100644 index 00000000..b3921d1f --- /dev/null +++ b/sqlx-core/src/sqlite/database.rs @@ -0,0 +1,35 @@ +use crate::database::{Database, HasCursor, HasRawValue, HasRow}; +use crate::sqlite::arguments::SqliteValue; + +/// **Sqlite** database driver. +pub struct Sqlite; + +impl Database for Sqlite { + type Connection = super::SqliteConnection; + + type Arguments = super::SqliteArguments; + + type TypeInfo = super::SqliteTypeInfo; + + // TODO? + type TableId = u32; + + type RawBuffer = Vec; +} + +impl<'a> HasRow<'a> for Sqlite { + type Database = Sqlite; + + type Row = super::SqliteRow<'a>; +} + +impl<'s, 'q> HasCursor<'s, 'q> for Sqlite { + type Database = Sqlite; + + type Cursor = super::SqliteCursor<'s, 'q>; +} + +impl<'a> HasRawValue<'a> for Sqlite { + // TODO + type RawValue = Option<()>; +} diff --git a/sqlx-core/src/sqlite/error.rs b/sqlx-core/src/sqlite/error.rs new file mode 100644 index 00000000..aa5713ad --- /dev/null +++ b/sqlx-core/src/sqlite/error.rs @@ -0,0 +1,11 @@ +use crate::error::DatabaseError; + +pub struct SqliteError; + +impl DatabaseError for SqliteError { + fn message(&self) -> &str { + todo!() + } +} + +impl_fmt_error!(SqliteError); diff --git a/sqlx-core/src/sqlite/executor.rs b/sqlx-core/src/sqlite/executor.rs new file mode 100644 index 00000000..cd38dcf6 --- /dev/null +++ b/sqlx-core/src/sqlite/executor.rs @@ -0,0 +1,53 @@ +use futures_core::future::BoxFuture; + +use crate::cursor::Cursor; +use crate::describe::Describe; +use crate::executor::{Execute, Executor, RefExecutor}; +use crate::sqlite::cursor::SqliteCursor; +use crate::sqlite::Sqlite; + +impl Executor for super::SqliteConnection { + type Database = Sqlite; + + fn execute<'e, 'q, E: 'e>(&'e mut self, query: E) -> BoxFuture<'e, crate::Result> + where + E: Execute<'q, Self::Database>, + { + // Box::pin(async move { + // let (query, arguments) = query.into_parts(); + // + // self.run(query, arguments).await?; + // self.affected_rows().await + // }) + todo!() + } + + fn fetch<'q, E>(&mut self, query: E) -> SqliteCursor<'_, 'q> + where + E: Execute<'q, Self::Database>, + { + SqliteCursor::from_connection(self, query) + } + + fn describe<'e, 'q, E: 'e>( + &'e mut self, + query: E, + ) -> BoxFuture<'e, crate::Result>> + where + E: Execute<'q, Self::Database>, + { + // Box::pin(async move { self.describe(query.into_parts().0).await }) + todo!() + } +} + +impl<'c> RefExecutor<'c> for &'c mut super::SqliteConnection { + type Database = Sqlite; + + fn fetch_by_ref<'q, E>(self, query: E) -> SqliteCursor<'c, 'q> + where + E: Execute<'q, Self::Database>, + { + SqliteCursor::from_connection(self, query) + } +} diff --git a/sqlx-core/src/sqlite/mod.rs b/sqlx-core/src/sqlite/mod.rs new file mode 100644 index 00000000..32ec2b87 --- /dev/null +++ b/sqlx-core/src/sqlite/mod.rs @@ -0,0 +1,16 @@ +mod arguments; +mod connection; +mod cursor; +mod database; +mod error; +mod executor; +mod row; +mod types; + +pub use arguments::SqliteArguments; +pub use connection::SqliteConnection; +pub use cursor::SqliteCursor; +pub use database::Sqlite; +pub use error::SqliteError; +pub use row::SqliteRow; +pub use types::SqliteTypeInfo; diff --git a/sqlx-core/src/sqlite/row.rs b/sqlx-core/src/sqlite/row.rs new file mode 100644 index 00000000..655611f7 --- /dev/null +++ b/sqlx-core/src/sqlite/row.rs @@ -0,0 +1,38 @@ +use core::str::{from_utf8, Utf8Error}; + +use std::collections::HashMap; +use std::convert::TryFrom; +use std::sync::Arc; + +use crate::error::UnexpectedNullError; +use crate::row::{ColumnIndex, Row}; +use crate::sqlite::Sqlite; + +pub struct SqliteRow<'c> { + c: std::marker::PhantomData<&'c ()>, +} + +impl<'c> Row<'c> for SqliteRow<'c> { + type Database = Sqlite; + + fn len(&self) -> usize { + todo!() + } + + fn try_get_raw<'r, I>(&'r self, index: I) -> crate::Result> + where + I: ColumnIndex, + { + todo!() + // let index = index.resolve(self)?; + // let buffer = self.data.get(index); + // + // buffer + // .map(|buf| match self.formats[index] { + // TypeFormat::Binary => Ok(PgValue::Binary(buf)), + // TypeFormat::Text => Ok(PgValue::Text(from_utf8(buf)?)), + // }) + // .transpose() + // .map_err(|err: Utf8Error| crate::Error::Decode(Box::new(err))) + } +} diff --git a/sqlx-core/src/sqlite/types/mod.rs b/sqlx-core/src/sqlite/types/mod.rs new file mode 100644 index 00000000..85acabbe --- /dev/null +++ b/sqlx-core/src/sqlite/types/mod.rs @@ -0,0 +1,18 @@ +use std::fmt::{self, Display}; + +use crate::types::TypeInfo; + +#[derive(Debug, Clone)] +pub struct SqliteTypeInfo {} + +impl Display for SqliteTypeInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + todo!() + } +} + +impl TypeInfo for SqliteTypeInfo { + fn compatible(&self, other: &Self) -> bool { + todo!() + } +} diff --git a/sqlx-macros/Cargo.toml b/sqlx-macros/Cargo.toml index 01a9bda6..231e4bed 100644 --- a/sqlx-macros/Cargo.toml +++ b/sqlx-macros/Cargo.toml @@ -24,6 +24,7 @@ runtime-tokio = [ "sqlx/runtime-tokio", "tokio", "lazy_static" ] # database mysql = [ "sqlx/mysql" ] postgres = [ "sqlx/postgres" ] +sqlite = [ "sqlx/sqlite" ] # type chrono = [ "sqlx/chrono" ]