Add test
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Kasper Juul Hermansen 2022-04-02 21:58:23 +02:00
parent 63f4dce705
commit 4fd34f973f
20 changed files with 987 additions and 133 deletions

View File

@ -0,0 +1,18 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Test" type="CargoCommandRunConfiguration" factoryName="Cargo Command" nameIsGenerated="true">
<option name="command" value="test" />
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
<option name="channel" value="DEFAULT" />
<option name="requiredFeatures" value="true" />
<option name="allFeatures" value="false" />
<option name="emulateTerminal" value="false" />
<option name="withSudo" value="false" />
<option name="backtrace" value="SHORT" />
<envs />
<option name="isRedirectInput" value="false" />
<option name="redirectInputPath" value="" />
<method v="2">
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
</method>
</configuration>
</component>

View File

@ -2,6 +2,8 @@
<module type="CPP_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/sqlite_bin/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/sqlite_core/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>

541
Cargo.lock generated
View File

@ -11,6 +11,29 @@ dependencies = [
"memchr",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base-x"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b"
[[package]]
name = "bincode"
version = "2.0.0-rc.1"
@ -29,6 +52,35 @@ dependencies = [
"virtue",
]
[[package]]
name = "bumpalo"
version = "3.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "colored"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
dependencies = [
"atty",
"lazy_static",
"winapi",
]
[[package]]
name = "const_fn"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935"
[[package]]
name = "const_format"
version = "0.2.22"
@ -49,18 +101,213 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"lazy_static",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
dependencies = [
"cfg-if",
"lazy_static",
]
[[package]]
name = "darling"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]]
name = "derive-new"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "derive_builder"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0"
dependencies = [
"darling",
"derive_builder_core",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "derive_builder_core"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "discard"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.121"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f"
[[package]]
name = "log"
version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
version = "1.0.36"
@ -79,6 +326,31 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rayon"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
dependencies = [
"autocfg",
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"lazy_static",
"num_cpus",
]
[[package]]
name = "regex"
version = "1.5.5"
@ -96,6 +368,55 @@ version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rspec"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89389e7c690310e855df3d9b507985ca0d323e2e766b2fedf369b02671e70e0a"
dependencies = [
"colored",
"derive-new",
"derive_builder",
"rayon",
"time",
]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
]
[[package]]
name = "ryu"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.136"
@ -117,10 +438,44 @@ dependencies = [
]
[[package]]
name = "sqlite_clone"
name = "serde_json"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sha1"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770"
dependencies = [
"sha1_smol",
]
[[package]]
name = "sha1_smol"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
[[package]]
name = "sqlite_bin"
version = "0.1.0"
dependencies = [
"sqlite_core",
]
[[package]]
name = "sqlite_core"
version = "0.1.0"
dependencies = [
"bincode",
"rspec",
"serde",
"sscanf",
]
@ -149,6 +504,70 @@ dependencies = [
"syn",
]
[[package]]
name = "standback"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff"
dependencies = [
"version_check",
]
[[package]]
name = "stdweb"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5"
dependencies = [
"discard",
"rustc_version",
"stdweb-derive",
"stdweb-internal-macros",
"stdweb-internal-runtime",
"wasm-bindgen",
]
[[package]]
name = "stdweb-derive"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
dependencies = [
"proc-macro2",
"quote",
"serde",
"serde_derive",
"syn",
]
[[package]]
name = "stdweb-internal-macros"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
dependencies = [
"base-x",
"proc-macro2",
"quote",
"serde",
"serde_derive",
"serde_json",
"sha1",
"syn",
]
[[package]]
name = "stdweb-internal-runtime"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
[[package]]
name = "strsim"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
name = "syn"
version = "1.0.89"
@ -160,14 +579,134 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "time"
version = "0.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242"
dependencies = [
"const_fn",
"libc",
"standback",
"stdweb",
"time-macros",
"version_check",
"winapi",
]
[[package]]
name = "time-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1"
dependencies = [
"proc-macro-hack",
"time-macros-impl",
]
[[package]]
name = "time-macros-impl"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f"
dependencies = [
"proc-macro-hack",
"proc-macro2",
"quote",
"standback",
"syn",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "virtue"
version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "757cfbfe0d17ee6f22fe97e536d463047d451b47cf9d11e2b7d1398b0ef274dd"
[[package]]
name = "wasm-bindgen"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -1,11 +1,6 @@
[package]
name = "sqlite_clone"
version = "0.1.0"
edition = "2021"
[workspace]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
sscanf = {version="0.2.1"}
bincode = "2.0.0-rc.1"
serde = {version="1.0.136", features=["derive"]}
members = [
"sqlite_core",
"sqlite_bin"
]

9
sqlite_bin/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "sqlite_bin"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
sqlite_core = { path = "../sqlite_core" }

9
sqlite_bin/src/main.rs Normal file
View File

@ -0,0 +1,9 @@
use sqlite_core::app::App;
use std::process::exit;
fn main() -> Result<(), String> {
App::new()
.with_commandline_interaction()
.with_on_exit_handler(|| exit(0))
.run()
}

14
sqlite_core/Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "sqlite_core"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
sscanf = { version = "0.2.1" }
bincode = "2.0.0-rc.1"
serde = { version = "1.0.136", features = ["derive"] }
[dev_dependencies]
rspec = "1.0"

71
sqlite_core/src/app.rs Normal file
View File

@ -0,0 +1,71 @@
use crate::input_buffer::InputBuffer;
use crate::interaction::{buffer::Buffer, command_line::CommandLine, Interaction};
use std::fmt::{Debug, Formatter};
use std::sync::{Arc, Mutex};
pub struct App {
interaction: Option<Arc<dyn Interaction + Send + Sync>>,
on_exit: fn(),
}
impl Default for App {
fn default() -> Self {
App::new()
}
}
impl Debug for App {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("App").finish()
}
}
impl App {
pub fn new() -> Self {
Self {
interaction: None,
on_exit: || {},
}
}
pub fn with_interaction(
&mut self,
interaction: Arc<dyn Interaction + Send + Sync>,
) -> &mut App {
self.interaction = Some(interaction);
self
}
pub fn with_commandline_interaction(&mut self) -> &mut Self {
self.with_interaction(Arc::new(CommandLine::new()))
}
pub fn with_buffer_interaction(
&mut self,
in_buffer: Arc<Mutex<Vec<String>>>,
out_buffer: Arc<Mutex<Vec<String>>>,
) -> &mut Self {
self.with_interaction(Arc::new(Buffer::new(in_buffer, out_buffer)))
}
pub fn with_on_exit_handler(&mut self, on_exit: fn()) -> &mut Self {
self.on_exit = on_exit;
self
}
pub fn run(&mut self) -> Result<(), String> {
if let None = self.interaction {
return Err(String::from("missing interaction"));
}
let mut input_buffer = InputBuffer::new(self.interaction.take().unwrap());
loop {
input_buffer
.print_prompt()
.read_input()?
.parse(self.on_exit);
}
}
}

View File

@ -0,0 +1,92 @@
use crate::interaction::Interaction;
use crate::statement::{ExecuteResult, StatementResultType};
use crate::table::Table;
use crate::{interaction, statement};
use std::ops::Deref;
use std::sync::Arc;
pub struct InputBuffer {
buffer: Option<String>,
table: Table,
interaction: Arc<dyn interaction::Interaction>,
}
impl InputBuffer {
pub fn new(interaction: Arc<dyn Interaction>) -> Self {
return Self {
buffer: None,
table: Table::new(),
interaction,
};
}
pub fn print_prompt(&mut self) -> &mut Self {
self.interaction.output(String::from("db > "));
self
}
pub fn read_input(&mut self) -> Result<&mut Self, String> {
self.buffer = Some(String::new());
match &mut self.buffer {
Some(input_buffer) => {
if let Ok(input) = self.interaction.input() {
*input_buffer = input.to_string();
Ok(self)
} else {
Err(String::from("could not handle input"))
}
}
_ => Err(String::from("Could not initialize buffer")),
}
}
pub fn parse(&mut self, on_exit: fn() -> ()) {
match &self.buffer {
Some(command) => {
if command.starts_with(".") {
Self::handle_meta_statement(command, on_exit);
} else {
match Self::prepare_statement(&command.replace("\n", "")) {
Ok(statement) => {
let execution_result = statement.execute(&mut self.table);
match execution_result {
ExecuteResult::Success {
statement_result_type: StatementResultType::Insert,
} => self
.interaction
.deref()
.output(String::from("insert success\n")),
ExecuteResult::Success {
statement_result_type: StatementResultType::Select { rows },
} => {
for row in rows {
self.interaction.output(row.print())
}
self.interaction.output(String::from("select success\n"))
}
_ => self.interaction.output(String::from("failure\n")),
}
}
Err(e) => {
self.interaction.output(format!("{}\n", e));
}
}
}
}
None => {}
}
}
fn prepare_statement(command: &String) -> Result<statement::Statement, String> {
return statement::Statement::parse_statement(command);
}
fn handle_meta_statement(command: &String, on_exit: fn()) {
match command.replace("\n", "").trim() {
".exit" => on_exit(),
cmd => {
println!("Could not handle command: {cmd}")
}
}
}
}

View File

@ -0,0 +1,33 @@
use std::sync::{Arc, Mutex};
use crate::interaction::Interaction;
pub struct Buffer {
int_buffer: Arc<Mutex<Vec<String>>>,
out_buffer: Arc<Mutex<Vec<String>>>,
}
impl Buffer {
pub fn new(int_buffer: Arc<Mutex<Vec<String>>>, out_buffer: Arc<Mutex<Vec<String>>>) -> Self {
Self {
int_buffer,
out_buffer,
}
}
}
impl Interaction for Buffer {
fn input(&self) -> Result<String, String> {
let mut int_buffer = self.int_buffer.lock().unwrap();
if let Some(input_string) = int_buffer.pop() {
Ok(input_string)
} else {
Err(String::from("internal_buffer is empty"))
}
}
fn output(&self, output: String) {
let mut out_buffer = self.out_buffer.lock().unwrap();
out_buffer.push(output)
}
}

View File

@ -0,0 +1,26 @@
use crate::interaction::Interaction;
use std::io::Write;
pub struct CommandLine {}
impl CommandLine {
pub fn new() -> Self {
Self {}
}
}
impl Interaction for CommandLine {
fn input(&self) -> Result<String, String> {
let buffer: &mut String = &mut String::new();
if let Ok(_) = std::io::stdin().read_line(buffer) {
return Ok(buffer.to_string());
} else {
return Err(String::from("could not read input buffer"));
}
}
fn output(&self, output: String) {
let _ = std::io::stdout().write(output.as_bytes());
let _ = std::io::stdout().flush();
}
}

View File

@ -0,0 +1,7 @@
pub mod buffer;
pub mod command_line;
pub trait Interaction {
fn input(&self) -> Result<String, String>;
fn output(&self, output: String);
}

8
sqlite_core/src/lib.rs Normal file
View File

@ -0,0 +1,8 @@
pub mod app;
mod input_buffer;
mod interaction;
mod page;
mod pager;
mod row;
mod statement;
mod table;

View File

@ -7,9 +7,7 @@ pub struct Page {
impl Page {
pub fn new(buffer: Vec<u8>) -> Self {
Self {
buffer,
}
Self { buffer }
}
}

View File

@ -1,9 +1,9 @@
use std::{iter, slice};
use std::io::Write;
use std::{iter, slice};
use bincode::{Decode, Encode};
use bincode::config::Configuration;
use bincode::error::{DecodeError, EncodeError};
use bincode::{Decode, Encode};
const COLUMN_USERNAME_SIZE: usize = 32;
const COLUMN_EMAIL_SIZE: usize = 255;
@ -18,8 +18,8 @@ pub struct Row {
pub trait Serialize {
fn serialize(&self) -> Result<Vec<u8>, EncodeError>;
fn deserialize(buffer: &[u8]) -> Result<Self, DecodeError>
where
Self: Sized;
where
Self: Sized;
}
impl Serialize for Row {
@ -61,9 +61,13 @@ impl Row {
}
}
pub(crate) fn print(&self) {
println!("({}, {}, {})", self.id, String::from_utf8(self.email.to_vec()).unwrap(), String::from_utf8(self.username.to_vec()).unwrap())
pub fn print(&self) -> String {
format!(
"({}, {}, {})",
self.id,
String::from_utf8(self.email.to_vec()).unwrap(),
String::from_utf8(self.username.to_vec()).unwrap()
)
}
}

View File

@ -1,16 +1,24 @@
use crate::row;
use crate::row::Serialize;
use crate::table::Table;
use crate::{row};
pub enum StatementType {
Insert { row: row::Row },
Select,
}
pub enum StatementResultType {
Insert,
Select { rows: Vec<row::Row> },
}
pub enum ExecuteResult {
Error { error: String },
Success,
Error {
error: String,
},
Success {
statement_result_type: StatementResultType,
},
}
pub struct Statement {
@ -44,7 +52,7 @@ impl Statement {
}
}
pub(crate) fn execute(&self, table: &mut Table) -> ExecuteResult {
pub fn execute(&self, table: &mut Table) -> ExecuteResult {
match &self.statement_type {
StatementType::Insert { row } => match row.serialize() {
Err(e) => ExecuteResult::Error {
@ -52,16 +60,17 @@ impl Statement {
},
Ok(serialization) => {
table.append_row(serialization);
ExecuteResult::Success
ExecuteResult::Success {
statement_result_type: StatementResultType::Insert {},
}
}
},
StatementType::Select => {
let rows = table.get_rows();
for row in rows {
row.print()
}
return ExecuteResult::Success;
return ExecuteResult::Success {
statement_result_type: StatementResultType::Select { rows },
};
}
}
}

View File

@ -1,9 +1,9 @@
use crate::pager::Pager;
use crate::row;
use std::mem::size_of;
use std::ops::DerefMut;
use crate::row::Row;
use crate::row::Serialize;
use std::mem::size_of;
use std::ops::DerefMut;
const PAGE_SIZE: usize = 4096;
@ -20,7 +20,7 @@ impl Table {
}
}
pub(crate) fn append_row(&mut self, row: Vec<u8>) {
pub fn append_row(&mut self, row: Vec<u8>) {
let row_size = size_of::<row::Row>();
let page_num = self.num_rows / self.rows_per_page(row_size);
let row_offset = self.num_rows % self.rows_per_page(row_size);
@ -50,7 +50,7 @@ impl Table {
PAGE_SIZE / row_size
}
pub(crate) fn get_rows(&mut self) -> Vec<Row> {
pub fn get_rows(&mut self) -> Vec<Row> {
let mut rows: Vec<Row> = Vec::with_capacity(self.num_rows);
for i in 0..self.num_rows {
rows.push(self.row(i))

View File

@ -0,0 +1,118 @@
use std::ops::Deref;
use std::sync::{Arc, Mutex};
use sqlite_core::app::App;
#[derive(Clone, Debug, Default)]
struct EmptyDatabaseEnv {
input: Arc<Mutex<Vec<String>>>,
output: Arc<Mutex<Vec<String>>>,
app: Arc<Mutex<sqlite_core::app::App>>,
}
#[test]
fn integration_test() {
let env = EmptyDatabaseEnv {
input: Arc::new(Mutex::new(Vec::new())),
output: Arc::new(Mutex::new(Vec::new())),
app: Arc::new(Mutex::new(App::new())),
};
rspec::run(&rspec::given("a sqlite database", env, |ctx| {
ctx.before_each(|env| {
env.input = Arc::new(Mutex::new(Vec::new()));
env.output = Arc::new(Mutex::new(Vec::new()));
env.app = Arc::new(Mutex::new(App::new()));
});
ctx.when("it runs with empty items", |ctx| {
ctx.then("it returns input error", |value| {
let result = value
.app
.lock()
.as_mut()
.unwrap()
.with_buffer_interaction(value.input.clone(), value.output.clone())
.run();
assert_eq!(result, Err(String::from("could not handle input")));
assert_eq!(0, value.input.lock().unwrap().deref().len());
assert_eq!(1, value.output.lock().unwrap().deref().len());
assert_eq!(
String::from("db > "),
value.output.lock().unwrap().deref()[0]
);
})
});
ctx.when("it runs with insert items", |ctx| {
ctx.before_all(|value| {
let mut input = value.input.lock().unwrap();
input.push(String::from("insert 1 username user@email.com"));
input.push(String::from("insert 2 username2 user2@email.com"));
input.push(String::from(".exit"));
input.reverse();
});
ctx.then("returns success", |value| {
let result = value
.app
.lock()
.as_mut()
.unwrap()
.with_buffer_interaction(value.input.clone(), value.output.clone())
.run();
assert_eq!(result, Err(String::from("could not handle input")));
assert_eq!(6, value.output.lock().unwrap().deref().len());
assert_eq!(
String::from("db > "),
value.output.lock().unwrap().deref()[0]
);
assert_eq!(
String::from("insert success\n"),
value.output.lock().unwrap().deref()[1]
);
assert_eq!(
String::from("db > "),
value.output.lock().unwrap().deref()[2]
);
assert_eq!(
String::from("insert success\n"),
value.output.lock().unwrap().deref()[3]
);
assert_eq!(
String::from("db > "),
value.output.lock().unwrap().deref()[4]
);
assert_eq!(
String::from("db > "),
value.output.lock().unwrap().deref()[5]
);
});
});
ctx.when("it runs with select items", |ctx| {
ctx.before_all(|value| {
let mut input = value.input.lock().unwrap();
input.push(String::from("insert 1 username user@email.com"));
input.push(String::from("insert 2 username2 user2@email.com"));
input.push(String::from("select"));
input.push(String::from(".exit"));
input.reverse();
});
ctx.then("returns success", |value| {
let result = value
.app
.lock()
.as_mut()
.unwrap()
.with_buffer_interaction(value.input.clone(), value.output.clone())
.run();
assert_eq!(result, Err(String::from("could not handle input")));
assert_eq!(10, value.output.lock().unwrap().deref().len());
});
});
}))
}

View File

@ -1,98 +0,0 @@
mod page;
mod pager;
mod row;
mod statement;
mod table;
use crate::statement::ExecuteResult;
use crate::table::Table;
use std::io;
use std::io::Write;
use std::process::exit;
struct InputBuffer {
buffer: Option<String>,
table: Table,
}
impl InputBuffer {
pub fn new() -> Self {
return Self {
buffer: None,
table: Table::new(),
};
}
pub(crate) fn print_prompt(&mut self) -> &mut Self {
print!("db > ");
if let Err(_) = io::stdout().flush() {
panic!("could not print to stdout")
}
self
}
pub(crate) fn read_input(&mut self) -> Result<&mut Self, String> {
self.buffer = Some(String::new());
match &mut self.buffer {
Some(input_buffer) => {
if let Ok(_) = io::stdin().read_line(input_buffer) {
Ok(self)
} else {
Err(String::from("could not handle input"))
}
}
_ => Err(String::from("Could not initialize buffer")),
}
}
pub(crate) fn parse(&mut self) {
match &self.buffer {
Some(command) => {
if command.starts_with(".") {
Self::handle_meta_statement(command);
} else {
match Self::prepare_statement(&command.replace("\n", "")) {
Ok(statement) => {
let execution_result = statement.execute(&mut self.table);
match execution_result {
ExecuteResult::Success => {
println!("success")
}
_ => {
println!("failure")
}
}
}
Err(e) => {
println!("{}", e);
}
}
}
}
None => {}
}
}
fn prepare_statement(command: &String) -> Result<statement::Statement, String> {
return statement::Statement::parse_statement(command);
}
fn handle_meta_statement(command: &String) {
match command.replace("\n", "").trim() {
".exit" => {
exit(0);
}
cmd => {
println!("Could not handle command: {cmd}")
}
}
}
}
fn main() -> Result<(), String> {
let mut input_buffer = InputBuffer::new();
loop {
input_buffer.print_prompt().read_input()?.parse()
}
}