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

Commit

Permalink
INSERT IGNORE WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Julius de Bruijn committed May 14, 2020
1 parent 3838d16 commit 8c721cb
Show file tree
Hide file tree
Showing 14 changed files with 844 additions and 132 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ num_cpus = "1.12"
rust_decimal = "=1.1.0"
futures = "0.3"
thiserror = "1.0"
hex = "0.4"

uuid = { version = "0.8", optional = true }
chrono = { version = "0.4", optional = true }
Expand Down
4 changes: 3 additions & 1 deletion src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ mod delete;
mod expression;
mod function;
mod grouping;
mod index;
mod insert;
mod join;
mod ops;
Expand All @@ -34,6 +35,7 @@ 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 use ops::*;
Expand All @@ -45,7 +47,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;
10 changes: 8 additions & 2 deletions src/ast/column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ use crate::ast::{Expression, ExpressionKind, Table};
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>>,
}

#[macro_export]
impl<'a> PartialEq for Column<'a> {
fn eq(&self, other: &Column) -> bool {
self.name == other.name && self.table == other.table
}
}

/// Marks a given string or a tuple as a column. Useful when using a column in
/// calculations, e.g.
///
Expand All @@ -30,6 +35,7 @@ pub struct Column<'a> {
/// sql
/// );
/// ```
#[macro_export]
macro_rules! col {
($e1:expr) => {
Expression::from(Column::from($e1))
Expand Down
11 changes: 11 additions & 0 deletions src/ast/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ pub struct Expression<'a> {
pub enum ExpressionKind<'a> {
/// Anything that we must parameterize before querying
Parameterized(Value<'a>),
/// A user-provided value we do not parameterize.
RawValue(Raw<'a>),
/// A database column
Column(Box<Column<'a>>),
/// Data in a row form, e.g. (1, 2, 3)
Expand Down Expand Up @@ -84,6 +86,15 @@ macro_rules! expression {
expression!(Row, Row);
expression!(Function, Function);

impl<'a> From<Raw<'a>> for Expression<'a> {
fn from(r: Raw<'a>) -> Self {
Expression {
kind: ExpressionKind::RawValue(r),
alias: None,
}
}
}

impl<'a> From<Values<'a>> for Expression<'a> {
fn from(p: Values<'a>) -> Self {
Expression {
Expand Down
25 changes: 25 additions & 0 deletions src/ast/index.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use super::Column;

#[derive(Debug, PartialEq, Clone)]
pub enum IndexDefinition<'a> {
Single(Column<'a>),
Compound(Vec<Column<'a>>),
}

impl<'a, T> From<T> for IndexDefinition<'a>
where
T: Into<Column<'a>>,
{
fn from(s: T) -> Self {
Self::Single(s.into())
}
}

impl<'a, T> From<Vec<T>> for IndexDefinition<'a>
where
T: Into<Column<'a>>,
{
fn from(s: Vec<T>) -> Self {
Self::Compound(s.into_iter().map(|c| c.into()).collect())
}
}
26 changes: 22 additions & 4 deletions src/ast/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::ast::*;
pub struct Insert<'a> {
pub(crate) table: Table<'a>,
pub(crate) columns: Vec<Column<'a>>,
pub(crate) values: Vec<Row<'a>>,
pub(crate) values: Expression<'a>,
pub(crate) on_conflict: Option<OnConflict>,
pub(crate) returning: Option<Vec<Column<'a>>>,
}
Expand Down Expand Up @@ -49,9 +49,9 @@ impl<'a> From<Insert<'a>> for Query<'a> {
impl<'a> From<SingleRowInsert<'a>> for Insert<'a> {
fn from(insert: SingleRowInsert<'a>) -> Self {
let values = if insert.values.is_empty() {
Vec::new()
Expression::from(Row::new())
} else {
vec![insert.values]
Expression::from(insert.values)
};

Insert {
Expand All @@ -66,10 +66,12 @@ impl<'a> From<SingleRowInsert<'a>> for Insert<'a> {

impl<'a> From<MultiRowInsert<'a>> for Insert<'a> {
fn from(insert: MultiRowInsert<'a>) -> Self {
let values = Expression::from(Values::new(insert.values));

Insert {
table: insert.table,
columns: insert.columns,
values: insert.values,
values,
on_conflict: None,
returning: None,
}
Expand Down Expand Up @@ -123,6 +125,22 @@ impl<'a> Insert<'a> {
}
}

pub fn expression_into<T, I, K, E>(table: T, columns: I, expression: E) -> Self
where
T: Into<Table<'a>>,
I: IntoIterator<Item = K>,
K: Into<Column<'a>>,
E: Into<Expression<'a>>,
{
Insert {
table: table.into(),
columns: columns.into_iter().map(|c| c.into()).collect(),
values: expression.into(),
on_conflict: None,
returning: None,
}
}

/// Sets the conflict resolution strategy.
pub fn on_conflict(mut self, on_conflict: OnConflict) -> Self {
self.on_conflict = Some(on_conflict);
Expand Down
9 changes: 9 additions & 0 deletions src/ast/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ impl<'a> Row<'a> {
}
}

impl<'a> IntoIterator for Row<'a> {
type Item = Expression<'a>;
type IntoIter = std::vec::IntoIter<Self::Item>;

fn into_iter(self) -> Self::IntoIter {
self.values.into_iter()
}
}

impl<'a, T> From<Vec<T>> for Row<'a>
where
T: Into<Expression<'a>>,
Expand Down
20 changes: 18 additions & 2 deletions src/ast/table.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::ExpressionKind;
use super::{ExpressionKind, IndexDefinition};
use crate::ast::{Expression, Row, Select, Values};
use std::borrow::Cow;

Expand All @@ -21,11 +21,18 @@ pub enum TableType<'a> {
}

/// A table definition
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug)]
pub struct Table<'a> {
pub typ: TableType<'a>,
pub alias: Option<Cow<'a, str>>,
pub database: Option<Cow<'a, str>>,
pub(crate) index_definitions: Vec<IndexDefinition<'a>>,
}

impl<'a> PartialEq for Table<'a> {
fn eq(&self, other: &Table) -> bool {
self.typ == other.typ && self.database == other.database
}
}

impl<'a> Table<'a> {
Expand All @@ -45,6 +52,11 @@ impl<'a> Table<'a> {
alias: None,
}
}

pub fn add_unique_index(mut self, i: impl Into<IndexDefinition<'a>>) -> Self {
self.index_definitions.push(i.into());
self
}
}

impl<'a> From<&'a str> for Table<'a> {
Expand All @@ -53,6 +65,7 @@ impl<'a> From<&'a str> for Table<'a> {
typ: TableType::Table(s.into()),
alias: None,
database: None,
index_definitions: Vec::new(),
}
}
}
Expand All @@ -70,6 +83,7 @@ impl<'a> From<String> for Table<'a> {
typ: TableType::Table(s.into()),
alias: None,
database: None,
index_definitions: Vec::new(),
}
}
}
Expand All @@ -86,6 +100,7 @@ impl<'a> From<Values<'a>> for Table<'a> {
typ: TableType::Values(values),
alias: None,
database: None,
index_definitions: Vec::new(),
}
}
}
Expand All @@ -103,6 +118,7 @@ impl<'a> From<Select<'a>> for Table<'a> {
typ: TableType::Query(select),
alias: None,
database: None,
index_definitions: Vec::new(),
}
}
}
Expand Down
21 changes: 19 additions & 2 deletions src/ast/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ use uuid::Uuid;
#[cfg(feature = "chrono-0_4")]
use chrono::{DateTime, Utc};

/// A value written to the query as-is without parameterization.
#[derive(Debug, Clone, PartialEq)]
pub struct Raw<'a>(pub(crate) Value<'a>);

pub trait IntoRaw<'a> {
fn raw(self) -> Raw<'a>;
}

impl<'a, T> IntoRaw<'a> for T
where
T: Into<Value<'a>>,
{
fn raw(self) -> Raw<'a> {
Raw(self.into())
}
}

/// A value we must parameterize for the prepared statement.
#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a> {
Expand Down Expand Up @@ -574,8 +591,8 @@ pub struct Values<'a> {

impl<'a> Values<'a> {
/// Create a new in-memory set of values.
pub fn new() -> Self {
Self::default()
pub fn new(rows: Vec<Row<'a>>) -> Self {
Self { rows }
}

/// Create a new in-memory set of values with an allocated capacity.
Expand Down
22 changes: 17 additions & 5 deletions src/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ use std::{borrow::Cow, fmt};
/// A function travelling through the query AST, building the final query string
/// and gathering parameters sent to the database together with the query.
pub trait Visitor<'a> {
/// Backtick character to surround identifiers, such as column and table names.
const C_BACKTICK: &'static str;
/// Opening backtick character to surround identifiers, such as column and table names.
const C_BACKTICK_OPEN: &'static str;
/// Closing backtick character to surround identifiers, such as column and table names.
const C_BACKTICK_CLOSE: &'static str;
/// Wildcard character to be used in `LIKE` queries.
const C_WILDCARD: &'static str;

Expand Down Expand Up @@ -76,6 +78,9 @@ pub trait Visitor<'a> {
/// What to use to substitute a parameter in the query.
fn visit_aggregate_to_string(&mut self, value: Expression<'a>) -> fmt::Result;

/// Visit a non-parameterized value.
fn visit_raw_value(&mut self, value: Value<'a>) -> fmt::Result;

/// A visit to a value we parameterize
fn visit_parameterized(&mut self, value: Value<'a>) -> fmt::Result {
self.add_parameter(value);
Expand Down Expand Up @@ -123,14 +128,18 @@ pub trait Visitor<'a> {
match table.typ {
TableType::Query(_) | TableType::Values(_) => match table.alias {
Some(ref alias) => {
self.surround_with(Self::C_BACKTICK, Self::C_BACKTICK, |ref mut s| s.write(alias))?;
self.surround_with(Self::C_BACKTICK_OPEN, Self::C_BACKTICK_CLOSE, |ref mut s| {
s.write(alias)
})?;
self.write(".*")?;
}
None => self.write("*")?,
},
TableType::Table(_) => match table.alias.clone() {
Some(ref alias) => {
self.surround_with(Self::C_BACKTICK, Self::C_BACKTICK, |ref mut s| s.write(alias))?;
self.surround_with(Self::C_BACKTICK_OPEN, Self::C_BACKTICK_CLOSE, |ref mut s| {
s.write(alias)
})?;
self.write(".*")?;
}
None => {
Expand Down Expand Up @@ -225,7 +234,9 @@ pub trait Visitor<'a> {
let len = parts.len();

for (i, parts) in parts.iter().enumerate() {
self.surround_with(Self::C_BACKTICK, Self::C_BACKTICK, |ref mut s| s.write(parts))?;
self.surround_with(Self::C_BACKTICK_OPEN, Self::C_BACKTICK_CLOSE, |ref mut s| {
s.write(parts)
})?;

if i < (len - 1) {
self.write(".")?;
Expand Down Expand Up @@ -319,6 +330,7 @@ pub trait Visitor<'a> {
ExpressionKind::ConditionTree(tree) => self.visit_conditions(tree)?,
ExpressionKind::Compare(compare) => self.visit_compare(compare)?,
ExpressionKind::Parameterized(val) => self.visit_parameterized(val)?,
ExpressionKind::RawValue(val) => self.visit_raw_value(val.0)?,
ExpressionKind::Column(column) => self.visit_column(*column)?,
ExpressionKind::Row(row) => self.visit_row(row)?,
ExpressionKind::Select(select) => self.surround_with("(", ")", |ref mut s| s.visit_select(*select))?,
Expand Down
Loading

0 comments on commit 8c721cb

Please sign in to comment.