Skip to content
This repository has been archived by the owner on Apr 25, 2023. It is now read-only.

Commit

Permalink
Support for Microsoft SQL Server
Browse files Browse the repository at this point in the history
  • Loading branch information
Julius de Bruijn committed Jun 8, 2020
1 parent e6d1207 commit ae0ec9d
Show file tree
Hide file tree
Showing 50 changed files with 5,629 additions and 1,096 deletions.
7 changes: 7 additions & 0 deletions .buildkite/docker.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/bin/bash

MYSQL_ROOT_PASSWORD=prisma
MSSQL_SA_PASSWORD="<YourStrong@Passw0rd>"

docker network create test-net
docker run --name test-postgres --network test-net \
Expand All @@ -14,9 +15,15 @@ docker run --name test-mysql --network test-net \
-e MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD \
-e MYSQL_PASSWORD=prisma -d mysql

docker run --name test-mssql --network test-net \
-e ACCEPT_EULA=Y \
-e SA_PASSWORD=$MSSQL_SA_PASSWORD \
-d mcr.microsoft.com/mssql/server:2019-latest

docker run -w /build --network test-net -v $BUILDKITE_BUILD_CHECKOUT_PATH:/build \
-e TEST_MYSQL=mysql://prisma:prisma@test-mysql:3306/prisma \
-e TEST_PSQL=postgres://prisma:prisma@test-postgres:5432/prisma \
-e TEST_MSSQL="sqlserver://test-mssql:1433;user=SA;password=$MSSQL_SA_PASSWORD;trustServerCertificate=true" \
prismagraphql/build:test cargo test --features full,json-1,uuid-0_8,chrono-0_4,tracing-log,serde-support

exit_code=$?
Expand Down
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export TEST_MYSQL=mysql://root:prisma@localhost:3306/prisma
export TEST_PSQL=postgres://postgres:prisma@localhost:5432/postgres
export TEST_MSSQL="sqlserver://localhost:1433;database=master;user=SA;password=<YourStrong@Passw0rd>;trustServerCertificate=true"
15 changes: 12 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,26 @@ features = [ "full", "serde-support", "json-1", "uuid-0_8", "chrono-0_4", "array
[features]
default = []

full = ["pooled", "sqlite", "json-1", "postgresql", "uuid-0_8", "chrono-0_4", "mysql"]
full = ["pooled", "sqlite", "json-1", "postgresql", "uuid-0_8", "chrono-0_4", "mysql", "mssql"]
full-postgresql = ["pooled", "postgresql", "json-1", "uuid-0_8", "chrono-0_4", "array"]
full-mysql = ["pooled", "mysql", "json-1", "uuid-0_8", "chrono-0_4"]
full-sqlite = ["pooled", "sqlite", "json-1", "uuid-0_8", "chrono-0_4"]
full-mssql = ["pooled", "mssql"]

single = ["sqlite", "json-1", "postgresql", "uuid-0_8", "chrono-0_4", "mysql"]
single-postgresql = ["postgresql", "json-1", "uuid-0_8", "chrono-0_4", "array"]
single-mysql = ["mysql", "json-1", "uuid-0_8", "chrono-0_4"]
single-sqlite = ["sqlite", "json-1", "uuid-0_8", "chrono-0_4"]
single-mssql = ["mssql"]

pooled = ["mobc"]
sqlite = ["rusqlite", "libsqlite3-sys", "tokio/sync"]
json-1 = ["serde_json", "base64"]
postgresql = ["rust_decimal/postgres", "native-tls", "tokio-postgres", "postgres-native-tls", "array", "bytes", "tokio", "bit-vec"]
postgresql = ["rust_decimal/tokio-pg", "native-tls", "tokio-postgres", "postgres-native-tls", "array", "bytes", "tokio", "bit-vec"]
uuid-0_8 = ["uuid"]
chrono-0_4 = ["chrono"]
mysql = ["mysql_async", "tokio"]
mssql = ["tiberius", "uuid-0_8", "chrono-0_4", "tokio-util"]
tracing-log = ["tracing", "tracing-core"]
array = []
serde-support = ["serde", "chrono/serde"]
Expand All @@ -51,10 +54,11 @@ metrics = "0.12"
percent-encoding = "2"
once_cell = "1.3"
num_cpus = "1.12"
rust_decimal = "=1.1.0"
rust_decimal = "1.6"
futures = "0.3"
thiserror = "1.0"
async-trait = "0.1"
hex = "0.4"

uuid = { version = "0.8", optional = true }
chrono = { version = "0.4", optional = true }
Expand All @@ -70,16 +74,21 @@ native-tls = { version = "0.2", optional = true }

mysql_async = { version = "0.23", optional = true }

tiberius = { git = "https://github.com/prisma/tiberius.git", optional = true, features = ["rust_decimal", "sql-browser-tokio"] }

log = { version = "0.4", features = ["release_max_level_trace"] }
tracing = { version = "0.1", optional = true }
tracing-core = { version = "0.1", optional = true }

mobc = { version = "0.5.7", optional = true }
bytes = { version = "0.5", optional = true }
tokio = { version = "0.2", features = ["rt-threaded", "macros", "sync"], optional = true}
tokio-util = { version = "0.3", features = ["compat"], optional = true }
serde = { version = "1.0", optional = true }
bit-vec = { version = "0.6.1", optional = true }

[dev-dependencies]
tokio = { version = "0.2", features = ["rt-threaded", "macros"]}
serde = { version = "1.0", features = ["derive"] }
indoc = "0.3"
names = "0.11"
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ Quaint is an abstraction over certain SQL databases. It provides:
- `full-postgresql`: Pooled support for PostgreSQL
- `full-mysql`: Pooled support for MySQL
- `full-sqlite`: Pooled support for SQLite
- `full-mssql`: Pooled support for Microsoft SQL Server
- `single`: All connectors, but no pooling
- `single-postgresql`: Single connection support for PostgreSQL
- `single-mysql`: Single connection support for MySQL
- `single-sqlite`: Single connection support for SQLite
- `single-mssql`: Single connection support for Microsoft SQL Server

### Goals:

Expand All @@ -43,8 +45,8 @@ choice.

### Testing:

- See `.envrc` for connection params. Override variables if different. MySQL and
PostgreSQL needs to be running for tests to succeed.
- See `.envrc` for connection params. Override variables if different. MySQL,
PostgreSQL and SQL Server needs to be running for tests to succeed.

Then:

Expand Down
6 changes: 5 additions & 1 deletion src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ mod delete;
mod expression;
mod function;
mod grouping;
mod index;
mod insert;
mod join;
mod merge;
mod ops;
mod ordering;
mod over;
Expand All @@ -34,8 +36,10 @@ pub use delete::Delete;
pub use expression::*;
pub use function::*;
pub use grouping::*;
pub use index::*;
pub use insert::*;
pub use join::{Join, JoinData, Joinable};
pub(crate) use merge::*;
pub use ops::*;
pub use ordering::{IntoOrderDefinition, Order, OrderDefinition, Orderable, Ordering};
pub use over::*;
Expand All @@ -45,7 +49,7 @@ pub use select::Select;
pub use table::*;
pub use union::Union;
pub use update::*;
pub use values::{Value, Values};
pub use values::{IntoRaw, Raw, Value, Values};

#[cfg(any(feature = "sqlite", feature = "mysql", feature = "postgresql"))]
pub(crate) use values::Params;
62 changes: 32 additions & 30 deletions src/ast/column.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,45 @@
use super::Aliasable;
use crate::ast::{Expression, ExpressionKind, Table};
use crate::{
ast::{Expression, ExpressionKind, Table},
Value,
};
use std::borrow::Cow;

/// A column definition.
#[derive(Clone, Debug, Default, PartialEq)]
#[derive(Clone, Debug, Default)]
pub struct Column<'a> {
pub name: Cow<'a, str>,
pub(crate) table: Option<Table<'a>>,
pub(crate) alias: Option<Cow<'a, str>>,
pub(crate) default: Option<Value<'a>>,
}

#[macro_export]
/// Marks a given string or a tuple as a column. Useful when using a column in
/// calculations, e.g.
///
/// ``` rust
/// # use quaint::{col, val, ast::*, visitor::{Visitor, Sqlite}};
/// let join = "dogs".on(("dogs", "slave_id").equals(Column::from(("cats", "master_id"))));
///
/// let query = Select::from_table("cats")
/// .value(Table::from("cats").asterisk())
/// .value(col!("dogs", "age") - val!(4))
/// .inner_join(join);
///
/// let (sql, params) = Sqlite::build(query);
///
/// assert_eq!(
/// "SELECT `cats`.*, (`dogs`.`age` - ?) FROM `cats` INNER JOIN `dogs` ON `dogs`.`slave_id` = `cats`.`master_id`",
/// sql
/// );
/// ```
macro_rules! col {
($e1:expr) => {
Expression::from(Column::from($e1))
};

($e1:expr, $e2:expr) => {
Expression::from(Column::from(($e1, $e2)))
};
impl<'a> PartialEq for Column<'a> {
fn eq(&self, other: &Column) -> bool {
self.name == other.name && self.table == other.table
}
}

impl<'a> Column<'a> {
/// Create a bare version of the column, stripping out all other information
/// other than the name.
pub(crate) fn into_bare(self) -> Self {
Self {
name: self.name,
table: None,
alias: None,
default: None,
}
}

/// Sets the default value for the column.
pub fn default<V>(mut self, value: V) -> Self
where
V: Into<Value<'a>>,
{
self.default = Some(value.into());
self
}
}

impl<'a> From<Column<'a>> for Expression<'a> {
Expand Down
Loading

0 comments on commit ae0ec9d

Please sign in to comment.