mirror of
https://github.com/fluencelabs/sqlite-wasm-connector
synced 2025-03-15 06:20:50 +00:00
Merge pull request #4 from fluencelabs/bind_binary_fix
Add some tests and move to rust 2018
This commit is contained in:
commit
fecc4c4e74
44
.circleci/config.yml
Normal file
44
.circleci/config.yml
Normal file
@ -0,0 +1,44 @@
|
||||
version: 2.1
|
||||
|
||||
orbs:
|
||||
docker: circleci/docker@1.5.0
|
||||
|
||||
jobs:
|
||||
sqlite_connector_rust_tests:
|
||||
docker:
|
||||
- image: circleci/rust:latest
|
||||
resource_class: xlarge
|
||||
environment:
|
||||
RUST_BACKTRACE: full
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- sqlite-connector01-{{ checksum "Cargo.lock" }}
|
||||
- run: |
|
||||
rustup toolchain install nightly-2021-05-21
|
||||
rustup default nightly-2021-05-21
|
||||
rustup override set nightly-2021-05-21
|
||||
|
||||
rustup component add rustfmt --toolchain nightly-2021-05-21
|
||||
rustup component add clippy --toolchain nightly-2021-05-21
|
||||
rustup target add wasm32-wasi
|
||||
|
||||
cargo install marine
|
||||
|
||||
cargo fmt --all -- --check --color always
|
||||
cargo check -v --all-features
|
||||
|
||||
./build.sh
|
||||
cargo test --release -v --all-features
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.cargo
|
||||
- ~/.rustup
|
||||
key: sqlite-connector01-{{ checksum "Cargo.lock" }}
|
||||
|
||||
workflows:
|
||||
version: 2.1
|
||||
marine:
|
||||
jobs:
|
||||
- sqlite_connector_rust_tests
|
14
.github/download_marine.sh
vendored
Executable file
14
.github/download_marine.sh
vendored
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
set -o pipefail -o errexit -o nounset
|
||||
set -x
|
||||
|
||||
MARINE_RELEASE="https://api.github.com/repos/fluencelabs/marine/releases/latest"
|
||||
OUT_DIR=/usr/local/bin
|
||||
|
||||
# get metadata about release
|
||||
curl -s -H "Accept: application/vnd.github.v3+json" $MARINE_RELEASE |
|
||||
# extract url and name for asset with name "marine"
|
||||
# also append $OUT_DIR to each name so file is saved to $OUT_DIR
|
||||
jq -r ".assets | .[] | select(.name == \"marine\") | \"\(.browser_download_url) $OUT_DIR/\(.name)\"" |
|
||||
# download assets
|
||||
xargs -n2 bash -c 'curl -L $0 -o $1 && chmod +x $1'
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,7 @@
|
||||
.idea/*
|
||||
|
||||
/artifacts
|
||||
.repl_history
|
||||
*.sqlite3
|
||||
Cargo.lock
|
||||
target
|
||||
|
23
.travis.yml
23
.travis.yml
@ -1,23 +0,0 @@
|
||||
language: rust
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
|
||||
script:
|
||||
- if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then
|
||||
cargo bench;
|
||||
cargo build;
|
||||
cargo test;
|
||||
else
|
||||
cargo build;
|
||||
cargo test;
|
||||
fi
|
||||
|
||||
notifications:
|
||||
email: false
|
@ -21,6 +21,7 @@ repository = "https://github.com/stainless-steel/sqlite"
|
||||
readme = "README.md"
|
||||
categories = ["api-bindings", "database"]
|
||||
keywords = ["database"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "marine_sqlite_connector"
|
||||
@ -39,3 +40,4 @@ marine-rs-sdk = "0.6.10"
|
||||
|
||||
[dev-dependencies]
|
||||
temporary = "0.6"
|
||||
marine-rs-sdk-test = "0.2.0"
|
||||
|
19
Config.toml
Normal file
19
Config.toml
Normal file
@ -0,0 +1,19 @@
|
||||
modules_dir = "artifacts/"
|
||||
|
||||
[[module]]
|
||||
name = "sqlite3"
|
||||
mem_pages_count = 100
|
||||
logger_enabled = false
|
||||
|
||||
[module.wasi]
|
||||
preopened_files = ["/tmp"]
|
||||
mapped_dirs = { "tmp" = "/tmp" }
|
||||
|
||||
[[module]]
|
||||
name = "test"
|
||||
mem_pages_count = 1
|
||||
logger_enabled = false
|
||||
|
||||
[module.wasi]
|
||||
preopened_files = ["/tmp"]
|
||||
mapped_dirs = { "tmp" = "/tmp" }
|
16
build.sh
Executable file
16
build.sh
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o errexit -o nounset -o pipefail
|
||||
|
||||
# set current working directory to script directory to run script from everywhere
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# build test.wasm
|
||||
marine build --release --bin test
|
||||
|
||||
# copy .wasm to artifacts
|
||||
rm -f artifacts/*
|
||||
mkdir -p artifacts
|
||||
cp target/wasm32-wasi/release/test.wasm artifacts/
|
||||
|
||||
# download SQLite 3 to use in tests
|
||||
curl -L https://github.com/fluencelabs/sqlite/releases/download/v0.15.0_w/sqlite3.wasm -o artifacts/sqlite3.wasm
|
@ -1,10 +1,9 @@
|
||||
use sqlite3_connector as ffi;
|
||||
use crate::sqlite3_connector as ffi;
|
||||
use crate::{Result, Statement};
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::path::Path;
|
||||
|
||||
use {Result, Statement};
|
||||
|
||||
/// A database connection.
|
||||
pub struct Connection {
|
||||
raw: ffi::Sqlite3DbHandle,
|
||||
@ -33,14 +32,14 @@ impl Connection {
|
||||
match result.ret_code {
|
||||
ffi::SQLITE_OK => {}
|
||||
code => {
|
||||
return match ::last_error(result.db_handle) {
|
||||
return match crate::last_error(result.db_handle) {
|
||||
Some(error) => {
|
||||
ffi::sqlite3_close(result.db_handle);
|
||||
Err(error)
|
||||
}
|
||||
_ => {
|
||||
ffi::sqlite3_close(result.db_handle);
|
||||
Err(::Error {
|
||||
Err(crate::Error {
|
||||
code: Some(code as isize),
|
||||
message: None,
|
||||
})
|
||||
@ -91,7 +90,7 @@ impl Connection {
|
||||
/// Create a prepared statement.
|
||||
#[inline]
|
||||
pub fn prepare<T: AsRef<str>>(&self, statement: T) -> Result<Statement> {
|
||||
::statement::new(self.raw, statement)
|
||||
crate::statement::new(self.raw, statement)
|
||||
}
|
||||
|
||||
/// Return the number of rows inserted, updated, or deleted by the most
|
||||
|
@ -1,6 +1,6 @@
|
||||
use sqlite3_connector as ffi;
|
||||
use statement::{State, Statement};
|
||||
use {Result, Value};
|
||||
use crate::sqlite3_connector as ffi;
|
||||
use crate::statement::{State, Statement};
|
||||
use crate::{Result, Value};
|
||||
|
||||
/// An iterator over rows.
|
||||
pub struct Cursor {
|
||||
|
@ -1,8 +1,6 @@
|
||||
#![allow(unused_variables)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
extern crate marine_rs_sdk;
|
||||
|
||||
use marine_rs_sdk::marine;
|
||||
|
||||
pub fn main() {}
|
||||
|
16
src/lib.rs
16
src/lib.rs
@ -4,7 +4,7 @@
|
||||
//!
|
||||
//! Open a connection, create a table, and insert some rows:
|
||||
//!
|
||||
//! ```
|
||||
//! ```ignore
|
||||
//! let connection = sqlite::open(":memory:").unwrap();
|
||||
//!
|
||||
//! connection
|
||||
@ -20,7 +20,7 @@
|
||||
//!
|
||||
//! Select some rows and process them one by one as plain text:
|
||||
//!
|
||||
//! ```
|
||||
//! ```ignore
|
||||
//! # let connection = sqlite::open(":memory:").unwrap();
|
||||
//! # connection
|
||||
//! # .execute(
|
||||
@ -44,7 +44,7 @@
|
||||
//! The same query using a prepared statement, which is much more efficient than
|
||||
//! the previous technique:
|
||||
//!
|
||||
//! ```
|
||||
//! ```ignore
|
||||
//! use sqlite::State;
|
||||
//! # let connection = sqlite::open(":memory:").unwrap();
|
||||
//! # connection
|
||||
@ -72,7 +72,7 @@
|
||||
//! The same query using a cursor, which is a wrapper around a prepared
|
||||
//! statement providing the concept of row and featuring all-at-once binding:
|
||||
//!
|
||||
//! ```
|
||||
//! ```ignore
|
||||
//! use sqlite::Value;
|
||||
//! # let connection = sqlite::open(":memory:").unwrap();
|
||||
//! # connection
|
||||
@ -108,9 +108,9 @@ use std::{error, fmt};
|
||||
|
||||
macro_rules! error(
|
||||
($connection:expr, $code:expr) => (
|
||||
match ::last_error($connection) {
|
||||
match crate::last_error($connection) {
|
||||
Some(error) => return Err(error),
|
||||
_ => return Err(::Error {
|
||||
_ => return Err(crate::Error {
|
||||
code: Some($code as isize),
|
||||
message: None,
|
||||
}),
|
||||
@ -121,7 +121,7 @@ macro_rules! error(
|
||||
macro_rules! ok_descr(
|
||||
($connection:expr, $result:expr) => (
|
||||
match $result.ret_code {
|
||||
::ffi::SQLITE_OK => {}
|
||||
crate::ffi::SQLITE_OK => {}
|
||||
code => error!($connection, code),
|
||||
}
|
||||
);
|
||||
@ -139,7 +139,7 @@ macro_rules! ok_descr(
|
||||
macro_rules! ok_raw(
|
||||
($connection:expr, $result:expr) => (
|
||||
match $result {
|
||||
::ffi::SQLITE_OK => {}
|
||||
crate::ffi::SQLITE_OK => {}
|
||||
code => error!($connection, code),
|
||||
}
|
||||
);
|
||||
|
@ -1,6 +1,4 @@
|
||||
extern crate marine_rs_sdk;
|
||||
|
||||
use self::marine_rs_sdk::marine;
|
||||
use marine_rs_sdk::marine;
|
||||
|
||||
pub(crate) type Sqlite3DbHandle = u32;
|
||||
pub(crate) type Sqlite3StmtHandle = u32;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use sqlite3_connector as ffi;
|
||||
use std::marker::PhantomData;
|
||||
use crate::sqlite3_connector as ffi;
|
||||
use crate::{Cursor, Result, Type, Value};
|
||||
|
||||
use {Cursor, Result, Type, Value};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// A prepared statement.
|
||||
pub struct Statement {
|
||||
@ -31,7 +31,7 @@ pub trait Readable: Sized {
|
||||
/// Read from a column.
|
||||
///
|
||||
/// The leftmost column has the index 0.
|
||||
fn read(&Statement, usize) -> Result<Self>;
|
||||
fn read(_: &Statement, _: usize) -> Result<Self>;
|
||||
}
|
||||
|
||||
impl Statement {
|
||||
@ -108,7 +108,7 @@ impl Statement {
|
||||
/// Upgrade to a cursor.
|
||||
#[inline]
|
||||
pub fn cursor(self) -> Cursor {
|
||||
::cursor::new(self)
|
||||
crate::cursor::new(self)
|
||||
}
|
||||
|
||||
/// Return the raw pointer.
|
||||
|
101
src/test.rs
101
src/test.rs
@ -1,8 +1,6 @@
|
||||
extern crate marine_rs_sdk;
|
||||
extern crate marine_sqlite_connector;
|
||||
|
||||
use marine_rs_sdk::marine;
|
||||
use marine_sqlite_connector::State;
|
||||
use marine_sqlite_connector::Value;
|
||||
|
||||
pub fn main() {}
|
||||
|
||||
@ -10,31 +8,6 @@ pub fn main() {}
|
||||
pub fn test1() {
|
||||
let connection = marine_sqlite_connector::open(":memory:").unwrap();
|
||||
|
||||
connection
|
||||
.execute(
|
||||
"
|
||||
CREATE TABLE users (name TEXT, age INTEGER);
|
||||
INSERT INTO users VALUES ('Alice', 42);
|
||||
INSERT INTO users VALUES ('Bob', 69);
|
||||
",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
connection
|
||||
.iterate("SELECT * FROM users WHERE age > 50", |pairs| {
|
||||
for &(column, value) in pairs.iter() {
|
||||
println!("{} = {}", column, value.unwrap());
|
||||
}
|
||||
true
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[marine]
|
||||
pub fn test2() {
|
||||
let connection = marine_sqlite_connector::open(":memory:").unwrap();
|
||||
|
||||
println!("connection id = {}\n", connection.as_raw());
|
||||
connection
|
||||
.execute(
|
||||
"
|
||||
@ -51,15 +24,13 @@ pub fn test2() {
|
||||
|
||||
statement.bind(1, 50).unwrap();
|
||||
|
||||
while let State::Row = statement.next().unwrap() {
|
||||
println!("name = {}", statement.read::<String>(0).unwrap());
|
||||
println!("age = {}", statement.read::<i64>(1).unwrap());
|
||||
}
|
||||
assert_eq!(statement.next().unwrap(), State::Row);
|
||||
assert_eq!(statement.read::<String>(0).unwrap(), "Bob");
|
||||
assert_eq!(statement.read::<i64>(1).unwrap(), 69);
|
||||
}
|
||||
#[marine]
|
||||
pub fn test3() {
|
||||
use marine_sqlite_connector::Value;
|
||||
|
||||
#[marine]
|
||||
pub fn test2() {
|
||||
let connection = marine_sqlite_connector::open(":memory:").unwrap();
|
||||
|
||||
connection
|
||||
@ -80,7 +51,63 @@ pub fn test3() {
|
||||
cursor.bind(&[Value::Integer(50)]).unwrap();
|
||||
|
||||
while let Some(row) = cursor.next().unwrap() {
|
||||
println!("name = {}", row[0].as_string().unwrap());
|
||||
println!("age = {}", row[1].as_integer().unwrap());
|
||||
assert_eq!(row[0].as_string().unwrap(), "Bob");
|
||||
assert_eq!(row[1].as_integer().unwrap(), 69);
|
||||
}
|
||||
}
|
||||
|
||||
#[marine]
|
||||
pub fn test3() {
|
||||
let connection = marine_sqlite_connector::open(":memory:").unwrap();
|
||||
|
||||
connection
|
||||
.execute(
|
||||
"
|
||||
CREATE TABLE test (number INTEGER, blob BLOB NOT NULL);
|
||||
",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut cursor = connection
|
||||
.prepare("INSERT OR REPLACE INTO test VALUES (?, ?)")
|
||||
.unwrap();
|
||||
|
||||
cursor.bind(1, &Value::Integer(50)).unwrap();
|
||||
cursor.bind(2, &Value::Binary(vec![1, 2, 3])).unwrap();
|
||||
|
||||
// check that blob is not null
|
||||
assert!(cursor.next().is_ok());
|
||||
}
|
||||
|
||||
#[marine]
|
||||
pub fn test4() {
|
||||
let connection = marine_sqlite_connector::open(":memory:").unwrap();
|
||||
|
||||
connection
|
||||
.execute(
|
||||
"
|
||||
CREATE TABLE test (number INTEGER, blob BLOB);
|
||||
",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut cursor = connection
|
||||
.prepare("INSERT OR REPLACE INTO test VALUES (?, ?)")
|
||||
.unwrap();
|
||||
|
||||
cursor.bind(1, &Value::Integer(50)).unwrap();
|
||||
cursor.bind(2, &Value::Binary(vec![1, 2, 3])).unwrap();
|
||||
|
||||
cursor.next().unwrap();
|
||||
|
||||
let mut cursor = connection
|
||||
.prepare("SELECT blob FROM test WHERE number = ?")
|
||||
.unwrap()
|
||||
.cursor();
|
||||
|
||||
cursor.bind(&[Value::Integer(50)]).unwrap();
|
||||
|
||||
while let Some(row) = cursor.next().unwrap() {
|
||||
assert_eq!(row[0].as_binary().unwrap().to_vec(), vec![1, 2, 3]);
|
||||
}
|
||||
}
|
||||
|
365
tests/lib.rs
365
tests/lib.rs
@ -1,365 +0,0 @@
|
||||
extern crate sqlite;
|
||||
extern crate temporary;
|
||||
|
||||
use sqlite::{Connection, OpenFlags, State, Type, Value};
|
||||
use std::path::Path;
|
||||
|
||||
macro_rules! ok(($result:expr) => ($result.unwrap()));
|
||||
|
||||
#[test]
|
||||
fn connection_changes() {
|
||||
let connection = setup_users(":memory:");
|
||||
assert_eq!(connection.changes(), 1);
|
||||
assert_eq!(connection.total_changes(), 1);
|
||||
|
||||
ok!(connection.execute("INSERT INTO users VALUES (2, 'Bob', NULL, NULL, NULL)"));
|
||||
assert_eq!(connection.changes(), 1);
|
||||
assert_eq!(connection.total_changes(), 2);
|
||||
|
||||
ok!(connection.execute("UPDATE users SET name = 'Bob' WHERE id = 1"));
|
||||
assert_eq!(connection.changes(), 1);
|
||||
assert_eq!(connection.total_changes(), 3);
|
||||
|
||||
ok!(connection.execute("DELETE FROM users"));
|
||||
assert_eq!(connection.changes(), 2);
|
||||
assert_eq!(connection.total_changes(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connection_error() {
|
||||
let connection = setup_users(":memory:");
|
||||
match connection.execute(":)") {
|
||||
Err(error) => assert_eq!(
|
||||
error.message,
|
||||
Some(String::from(r#"unrecognized token: ":""#))
|
||||
),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connection_iterate() {
|
||||
macro_rules! pair(
|
||||
($one:expr, $two:expr) => (($one, Some($two)));
|
||||
);
|
||||
|
||||
let connection = setup_users(":memory:");
|
||||
|
||||
let mut done = false;
|
||||
let statement = "SELECT * FROM users";
|
||||
ok!(connection.iterate(statement, |pairs| {
|
||||
assert_eq!(pairs.len(), 5);
|
||||
assert_eq!(pairs[0], pair!("id", "1"));
|
||||
assert_eq!(pairs[1], pair!("name", "Alice"));
|
||||
assert_eq!(pairs[2], pair!("age", "42.69"));
|
||||
assert_eq!(pairs[3], pair!("photo", "\x42\x69"));
|
||||
assert_eq!(pairs[4], ("email", None));
|
||||
done = true;
|
||||
true
|
||||
}));
|
||||
assert!(done);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connection_open_with_flags() {
|
||||
use temporary::Directory;
|
||||
|
||||
let directory = ok!(Directory::new("sqlite"));
|
||||
let path = directory.path().join("database.sqlite3");
|
||||
setup_users(&path);
|
||||
|
||||
let flags = OpenFlags::new().set_read_only();
|
||||
let connection = ok!(Connection::open_with_flags(path, flags));
|
||||
match connection.execute("INSERT INTO users VALUES (2, 'Bob', NULL, NULL)") {
|
||||
Err(_) => {}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn connection_set_busy_handler() {
|
||||
use std::thread;
|
||||
use temporary::Directory;
|
||||
|
||||
let directory = ok!(Directory::new("sqlite"));
|
||||
let path = directory.path().join("database.sqlite3");
|
||||
setup_users(&path);
|
||||
|
||||
let guards = (0..100)
|
||||
.map(|_| {
|
||||
let path = path.to_path_buf();
|
||||
thread::spawn(move || {
|
||||
let mut connection = ok!(sqlite::open(&path));
|
||||
ok!(connection.set_busy_handler(|_| true));
|
||||
let statement = "INSERT INTO users VALUES (?, ?, ?, ?, ?)";
|
||||
let mut statement = ok!(connection.prepare(statement));
|
||||
ok!(statement.bind(1, 2i64));
|
||||
ok!(statement.bind(2, "Bob"));
|
||||
ok!(statement.bind(3, 69.42));
|
||||
ok!(statement.bind(4, &[0x69u8, 0x42u8][..]));
|
||||
ok!(statement.bind(5, ()));
|
||||
assert_eq!(ok!(statement.next()), State::Done);
|
||||
true
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for guard in guards {
|
||||
assert!(ok!(guard.join()));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cursor_read() {
|
||||
let connection = setup_users(":memory:");
|
||||
ok!(connection.execute("INSERT INTO users VALUES (2, 'Bob', NULL, NULL, NULL)"));
|
||||
let statement = "SELECT id, age FROM users ORDER BY 1 DESC";
|
||||
let statement = ok!(connection.prepare(statement));
|
||||
|
||||
let mut count = 0;
|
||||
let mut cursor = statement.cursor();
|
||||
while let Some(row) = ok!(cursor.next()) {
|
||||
let id = row[0].as_integer().unwrap();
|
||||
if id == 1 {
|
||||
assert_eq!(row[1].as_float().unwrap(), 42.69);
|
||||
} else if id == 2 {
|
||||
assert_eq!(row[1].as_float().unwrap_or(69.42), 69.42);
|
||||
} else {
|
||||
assert!(false);
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
assert_eq!(count, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cursor_wildcard() {
|
||||
let connection = setup_english(":memory:");
|
||||
let statement = "SELECT value FROM english WHERE value LIKE '%type'";
|
||||
let statement = ok!(connection.prepare(statement));
|
||||
|
||||
let mut count = 0;
|
||||
let mut cursor = statement.cursor();
|
||||
while let Some(_) = ok!(cursor.next()) {
|
||||
count += 1;
|
||||
}
|
||||
assert_eq!(count, 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cursor_wildcard_with_binding() {
|
||||
let connection = setup_english(":memory:");
|
||||
let statement = "SELECT value FROM english WHERE value LIKE ?";
|
||||
let mut statement = ok!(connection.prepare(statement));
|
||||
ok!(statement.bind(1, "%type"));
|
||||
|
||||
let mut count = 0;
|
||||
let mut cursor = statement.cursor();
|
||||
while let Some(_) = ok!(cursor.next()) {
|
||||
count += 1;
|
||||
}
|
||||
assert_eq!(count, 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cursor_workflow() {
|
||||
let connection = setup_users(":memory:");
|
||||
|
||||
let select = "SELECT id, name FROM users WHERE id = ?";
|
||||
let mut select = ok!(connection.prepare(select)).cursor();
|
||||
|
||||
let insert = "INSERT INTO users (id, name) VALUES (?, ?)";
|
||||
let mut insert = ok!(connection.prepare(insert)).cursor();
|
||||
|
||||
for _ in 0..10 {
|
||||
ok!(select.bind(&[Value::Integer(1)]));
|
||||
assert_eq!(
|
||||
ok!(ok!(select.next())),
|
||||
&[Value::Integer(1), Value::String("Alice".to_string())]
|
||||
);
|
||||
assert_eq!(ok!(select.next()), None);
|
||||
}
|
||||
|
||||
ok!(select.bind(&[Value::Integer(42)]));
|
||||
assert_eq!(ok!(select.next()), None);
|
||||
|
||||
ok!(insert.bind(&[Value::Integer(42), Value::String("Bob".to_string())]));
|
||||
assert_eq!(ok!(insert.next()), None);
|
||||
|
||||
ok!(select.bind(&[Value::Integer(42)]));
|
||||
assert_eq!(
|
||||
ok!(ok!(select.next())),
|
||||
&[Value::Integer(42), Value::String("Bob".to_string())]
|
||||
);
|
||||
assert_eq!(ok!(select.next()), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn statement_bind() {
|
||||
let connection = setup_users(":memory:");
|
||||
let statement = "INSERT INTO users VALUES (?, ?, ?, ?, ?)";
|
||||
let mut statement = ok!(connection.prepare(statement));
|
||||
|
||||
ok!(statement.bind(1, 2i64));
|
||||
ok!(statement.bind(2, "Bob"));
|
||||
ok!(statement.bind(3, 69.42));
|
||||
ok!(statement.bind(4, &[0x69u8, 0x42u8][..]));
|
||||
ok!(statement.bind(5, ()));
|
||||
assert_eq!(ok!(statement.next()), State::Done);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn statement_bind_with_optional() {
|
||||
let connection = setup_users(":memory:");
|
||||
let statement = "INSERT INTO users VALUES (?, ?, ?, ?, ?)";
|
||||
let mut statement = ok!(connection.prepare(statement));
|
||||
|
||||
ok!(statement.bind(1, None::<i64>));
|
||||
ok!(statement.bind(2, None::<&str>));
|
||||
ok!(statement.bind(3, None::<f64>));
|
||||
ok!(statement.bind(4, None::<&[u8]>));
|
||||
ok!(statement.bind(5, None::<&str>));
|
||||
assert_eq!(ok!(statement.next()), State::Done);
|
||||
|
||||
let statement = "INSERT INTO users VALUES (?, ?, ?, ?, ?)";
|
||||
let mut statement = ok!(connection.prepare(statement));
|
||||
|
||||
ok!(statement.bind(1, Some(2i64)));
|
||||
ok!(statement.bind(2, Some("Bob")));
|
||||
ok!(statement.bind(3, Some(69.42)));
|
||||
ok!(statement.bind(4, Some(&[0x69u8, 0x42u8][..])));
|
||||
ok!(statement.bind(5, None::<&str>));
|
||||
assert_eq!(ok!(statement.next()), State::Done);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn statement_count() {
|
||||
let connection = setup_users(":memory:");
|
||||
let statement = "SELECT * FROM users";
|
||||
let mut statement = ok!(connection.prepare(statement));
|
||||
|
||||
assert_eq!(ok!(statement.next()), State::Row);
|
||||
|
||||
assert_eq!(statement.count(), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn statement_name() {
|
||||
let connection = setup_users(":memory:");
|
||||
let statement = "SELECT id, name, age, photo AS user_photo FROM users";
|
||||
let statement = ok!(connection.prepare(statement));
|
||||
|
||||
let names = statement.names();
|
||||
assert_eq!(names, vec!["id", "name", "age", "user_photo"]);
|
||||
assert_eq!("user_photo", statement.name(3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn statement_kind() {
|
||||
let connection = setup_users(":memory:");
|
||||
let statement = "SELECT * FROM users";
|
||||
let mut statement = ok!(connection.prepare(statement));
|
||||
|
||||
assert_eq!(statement.kind(0), Type::Null);
|
||||
assert_eq!(statement.kind(1), Type::Null);
|
||||
assert_eq!(statement.kind(2), Type::Null);
|
||||
assert_eq!(statement.kind(3), Type::Null);
|
||||
|
||||
assert_eq!(ok!(statement.next()), State::Row);
|
||||
|
||||
assert_eq!(statement.kind(0), Type::Integer);
|
||||
assert_eq!(statement.kind(1), Type::String);
|
||||
assert_eq!(statement.kind(2), Type::Float);
|
||||
assert_eq!(statement.kind(3), Type::Binary);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn statement_read() {
|
||||
let connection = setup_users(":memory:");
|
||||
let statement = "SELECT * FROM users";
|
||||
let mut statement = ok!(connection.prepare(statement));
|
||||
|
||||
assert_eq!(ok!(statement.next()), State::Row);
|
||||
assert_eq!(ok!(statement.read::<i64>(0)), 1);
|
||||
assert_eq!(ok!(statement.read::<String>(1)), String::from("Alice"));
|
||||
assert_eq!(ok!(statement.read::<f64>(2)), 42.69);
|
||||
assert_eq!(ok!(statement.read::<Vec<u8>>(3)), vec![0x42, 0x69]);
|
||||
assert_eq!(ok!(statement.read::<Value>(4)), Value::Null);
|
||||
assert_eq!(ok!(statement.next()), State::Done);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn statement_read_with_optional() {
|
||||
let connection = setup_users(":memory:");
|
||||
let statement = "SELECT * FROM users";
|
||||
let mut statement = ok!(connection.prepare(statement));
|
||||
|
||||
assert_eq!(ok!(statement.next()), State::Row);
|
||||
assert_eq!(ok!(statement.read::<Option<i64>>(0)), Some(1));
|
||||
assert_eq!(
|
||||
ok!(statement.read::<Option<String>>(1)),
|
||||
Some(String::from("Alice"))
|
||||
);
|
||||
assert_eq!(ok!(statement.read::<Option<f64>>(2)), Some(42.69));
|
||||
assert_eq!(
|
||||
ok!(statement.read::<Option<Vec<u8>>>(3)),
|
||||
Some(vec![0x42, 0x69])
|
||||
);
|
||||
assert_eq!(ok!(statement.read::<Option<String>>(4)), None);
|
||||
assert_eq!(ok!(statement.next()), State::Done);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn statement_wildcard() {
|
||||
let connection = setup_english(":memory:");
|
||||
let statement = "SELECT value FROM english WHERE value LIKE '%type'";
|
||||
let mut statement = ok!(connection.prepare(statement));
|
||||
|
||||
let mut count = 0;
|
||||
while let State::Row = ok!(statement.next()) {
|
||||
count += 1;
|
||||
}
|
||||
assert_eq!(count, 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn statement_wildcard_with_binding() {
|
||||
let connection = setup_english(":memory:");
|
||||
let statement = "SELECT value FROM english WHERE value LIKE ?";
|
||||
let mut statement = ok!(connection.prepare(statement));
|
||||
ok!(statement.bind(1, "%type"));
|
||||
|
||||
let mut count = 0;
|
||||
while let State::Row = ok!(statement.next()) {
|
||||
count += 1;
|
||||
}
|
||||
assert_eq!(count, 6);
|
||||
}
|
||||
|
||||
fn setup_english<T: AsRef<Path>>(path: T) -> Connection {
|
||||
let connection = ok!(sqlite::open(path));
|
||||
ok!(connection.execute(
|
||||
"
|
||||
CREATE TABLE english (value TEXT);
|
||||
INSERT INTO english VALUES ('cerotype');
|
||||
INSERT INTO english VALUES ('metatype');
|
||||
INSERT INTO english VALUES ('ozotype');
|
||||
INSERT INTO english VALUES ('phenotype');
|
||||
INSERT INTO english VALUES ('plastotype');
|
||||
INSERT INTO english VALUES ('undertype');
|
||||
INSERT INTO english VALUES ('nonsence');
|
||||
",
|
||||
));
|
||||
connection
|
||||
}
|
||||
|
||||
fn setup_users<T: AsRef<Path>>(path: T) -> Connection {
|
||||
let connection = ok!(sqlite::open(path));
|
||||
ok!(connection.execute(
|
||||
"
|
||||
CREATE TABLE users (id INTEGER, name TEXT, age REAL, photo BLOB, email TEXT);
|
||||
INSERT INTO users VALUES (1, 'Alice', 42.69, X'4269', NULL);
|
||||
",
|
||||
));
|
||||
connection
|
||||
}
|
39
tests/tests.rs
Normal file
39
tests/tests.rs
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2021 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
mod tests {
|
||||
use marine_rs_sdk_test::marine_test;
|
||||
|
||||
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
|
||||
fn test1(test: marine_test_env::test::ModuleInterface) {
|
||||
test.test1()
|
||||
}
|
||||
|
||||
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
|
||||
fn test2(test: marine_test_env::test::ModuleInterface) {
|
||||
test.test2()
|
||||
}
|
||||
|
||||
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
|
||||
fn test3(test: marine_test_env::test::ModuleInterface) {
|
||||
test.test3()
|
||||
}
|
||||
|
||||
#[marine_test(config_path = "../Config.toml", modules_dir = "../artifacts/")]
|
||||
fn test4(test: marine_test_env::test::ModuleInterface) {
|
||||
test.test4()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user