<commit_before>use crate::value::AMQPValue;

use std::{
    collections::BTreeMap,
    fmt,
};

use serde::{Deserialize, Serialize};

/// Enumeration referencing all the available AMQP types
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum AMQPType {
    /// A bool
    Boolean,
    /// An i8
    ShortShortInt,
    /// A u8
    ShortShortUInt,
    /// An i16
    ShortInt,
    /// A u16
    ShortUInt,
    /// An i32
    LongInt,
    /// A u32
    LongUInt,
    /// An i64
    LongLongInt,
    /// A u64
    LongLongUInt,
    /// An f32
    Float,
    /// An f64
    Double,
    /// A decimal value represented by a scale and a value
    DecimalValue,
    /// Deprecated, a String
    ShortString,
    /// A String
    LongString,
    /// An array of AMQPValue
    FieldArray,
    /// A timestamp (u32)
    Timestamp,
    /// A Map<String, AMQPValue>
    FieldTable,
    /// An array of bytes, RabbitMQ specific
    ByteArray, /* ByteArray is specific to RabbitMQ */
    /// No value
    Void,
}

impl AMQPType {
    /// Get the AMQPType corresponding to the given id.
    /// We don't strictly follow the spec here but rather the RabbitMQ implementation
    /// 's' means ShortInt (like 'U') instead of ShortString
    /// 'l' and 'L' both mean LongLongInt (no LongLongUInt)
    pub fn from_id(id: char) -> Option<AMQPType> {
        match id {
            't' => Some(AMQPType::Boolean),
            'b' => Some(AMQPType::ShortShortInt),
            'B' => Some(AMQPType::ShortShortUInt),
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            's' |
            'U' => Some(AMQPType::ShortInt),
            'u' => Some(AMQPType::ShortUInt),
            'I' => Some(AMQPType::LongInt),
            'i' => Some(AMQPType::LongUInt),
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            'L' |
            'l' => Some(AMQPType::LongLongInt),
            'f' => Some(AMQPType::Float),
            'd' => Some(AMQPType::Double),
            'D' => Some(AMQPType::DecimalValue),
            'S' => Some(AMQPType::LongString),
            'A' => Some(AMQPType::FieldArray),
            'T' => Some(AMQPType::Timestamp),
            'F' => Some(AMQPType::FieldTable),
            'x' => Some(AMQPType::ByteArray),
            'V' => Some(AMQPType::Void),
            _   => None,
        }
    }

    /// Get the id from an AMQPType
    /// We don't strictly follow the spec here but rather the RabbitMQ implementation
    /// ShortString doesn't have an id, we return '_' instead
    /// ShortInt is supposed to be 'U' but we use 's'
    /// LongLongUInt is supposed to be 'L' but we return 'l' as LongLongInt
    pub fn get_id(self) -> char {
        match self {
            AMQPType::Boolean        => 't',
            AMQPType::ShortShortInt  => 'b',
            AMQPType::ShortShortUInt => 'B',
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            AMQPType::ShortInt       => 's',
            AMQPType::ShortUInt      => 'u',
            AMQPType::LongInt        => 'I',
            AMQPType::LongUInt       => 'i',
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            AMQPType::LongLongInt    |
            AMQPType::LongLongUInt   => 'l',
            AMQPType::Float          => 'f',
            AMQPType::Double         => 'd',
            AMQPType::DecimalValue   => 'D',
            /* ShortString only exists for internal usage, we shouldn't ever have to use this */
            AMQPType::ShortString    => '_',
            AMQPType::LongString     => 'S',
            AMQPType::FieldArray     => 'A',
            AMQPType::Timestamp      => 'T',
            AMQPType::FieldTable     => 'F',
            AMQPType::ByteArray      => 'x',
            AMQPType::Void           => 'V',
        }
    }
}

impl fmt::Display for AMQPType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

/// A bool
pub type Boolean        = bool;
/// An i8
pub type ShortShortInt  = i8;
/// A u8
pub type ShortShortUInt = u8;
/// An i16
pub type ShortInt       = i16;
/// A u16
pub type ShortUInt      = u16;
/// An i32
pub type LongInt        = i32;
/// A u32
pub type LongUInt       = u32;
/// An i64
pub type LongLongInt    = i64;
/// A u64
pub type LongLongUInt   = u64;
/// A f32
pub type Float          = f32;
/// A f64
pub type Double         = f64;
/// A timestamp (u32)
pub type Timestamp      = LongLongUInt;
/// No value
pub type Void           = ();

/// A String (deprecated)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
pub struct ShortString(pub String);
/// A String
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
pub struct LongString(pub String);
/// An array of AMQPValue
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
pub struct FieldArray(pub Vec<AMQPValue>);
/// A Map<String, AMQPValue>
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
pub struct FieldTable(pub BTreeMap<ShortString, AMQPValue>);
/// An array of bytes (RabbitMQ specific)
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
pub struct ByteArray(pub Vec<u8>);

/// A Decimal value composed of a scale and a value
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct DecimalValue {
    /// The scale of the value
    pub scale: ShortShortUInt,
    /// The actual value
    pub value: LongUInt,
}

/// A Reference pointing to a ShortString
pub struct ShortStringRef<'a>(pub &'a str);
/// A Reference pointing to a LongString
pub struct LongStringRef<'a>(pub &'a str);

impl<'a> ShortString {
    /// Get a reference to a ShortString
    pub fn as_ref(&'a self) -> ShortStringRef<'a> {
        ShortStringRef(&self.0)
    }
}

impl From<&str> for ShortString {
    fn from(s: &str) -> Self {
        Self(s.to_owned())
    }
}

impl Default for ShortStringRef<'static> {
    fn default() -> Self {
        Self("")
    }
}

impl<'a> LongString {
    /// Get a reference to a LongString
    pub fn as_ref(&'a self) -> LongStringRef<'a> {
        LongStringRef(&self.0)
    }
}

impl From<&str> for LongString {
    fn from(s: &str) -> Self {
        Self(s.to_owned())
    }
}

impl Default for LongStringRef<'static> {
    fn default() -> Self {
        Self("")
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_type_from_id() {
        assert_eq!(AMQPType::from_id('T'), Some(AMQPType::Timestamp));
        assert_eq!(AMQPType::from_id('S'), Some(AMQPType::LongString));
        assert_eq!(AMQPType::from_id('s'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('U'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('l'), Some(AMQPType::LongLongInt));
        assert_eq!(AMQPType::from_id('z'), None);
    }

    #[test]
    fn test_type_get_id() {
        assert_eq!(AMQPType::LongLongInt.get_id(),  'l');
        assert_eq!(AMQPType::LongLongUInt.get_id(), 'l');
        assert_eq!(AMQPType::ShortString.get_id(),  '_');
    }

    #[test]
    fn test_type_to_string() {
        assert_eq!(AMQPType::Boolean.to_string(), "Boolean");
        assert_eq!(AMQPType::Void.to_string(),    "Void");
    }
}
<commit_msg>types: add more From impls<commit_after>use crate::value::AMQPValue;

use std::{
    collections::BTreeMap,
    fmt,
};

use serde::{Deserialize, Serialize};

/// Enumeration referencing all the available AMQP types
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub enum AMQPType {
    /// A bool
    Boolean,
    /// An i8
    ShortShortInt,
    /// A u8
    ShortShortUInt,
    /// An i16
    ShortInt,
    /// A u16
    ShortUInt,
    /// An i32
    LongInt,
    /// A u32
    LongUInt,
    /// An i64
    LongLongInt,
    /// A u64
    LongLongUInt,
    /// An f32
    Float,
    /// An f64
    Double,
    /// A decimal value represented by a scale and a value
    DecimalValue,
    /// Deprecated, a String
    ShortString,
    /// A String
    LongString,
    /// An array of AMQPValue
    FieldArray,
    /// A timestamp (u32)
    Timestamp,
    /// A Map<String, AMQPValue>
    FieldTable,
    /// An array of bytes, RabbitMQ specific
    ByteArray, /* ByteArray is specific to RabbitMQ */
    /// No value
    Void,
}

impl AMQPType {
    /// Get the AMQPType corresponding to the given id.
    /// We don't strictly follow the spec here but rather the RabbitMQ implementation
    /// 's' means ShortInt (like 'U') instead of ShortString
    /// 'l' and 'L' both mean LongLongInt (no LongLongUInt)
    pub fn from_id(id: char) -> Option<AMQPType> {
        match id {
            't' => Some(AMQPType::Boolean),
            'b' => Some(AMQPType::ShortShortInt),
            'B' => Some(AMQPType::ShortShortUInt),
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            's' |
            'U' => Some(AMQPType::ShortInt),
            'u' => Some(AMQPType::ShortUInt),
            'I' => Some(AMQPType::LongInt),
            'i' => Some(AMQPType::LongUInt),
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            'L' |
            'l' => Some(AMQPType::LongLongInt),
            'f' => Some(AMQPType::Float),
            'd' => Some(AMQPType::Double),
            'D' => Some(AMQPType::DecimalValue),
            'S' => Some(AMQPType::LongString),
            'A' => Some(AMQPType::FieldArray),
            'T' => Some(AMQPType::Timestamp),
            'F' => Some(AMQPType::FieldTable),
            'x' => Some(AMQPType::ByteArray),
            'V' => Some(AMQPType::Void),
            _   => None,
        }
    }

    /// Get the id from an AMQPType
    /// We don't strictly follow the spec here but rather the RabbitMQ implementation
    /// ShortString doesn't have an id, we return '_' instead
    /// ShortInt is supposed to be 'U' but we use 's'
    /// LongLongUInt is supposed to be 'L' but we return 'l' as LongLongInt
    pub fn get_id(self) -> char {
        match self {
            AMQPType::Boolean        => 't',
            AMQPType::ShortShortInt  => 'b',
            AMQPType::ShortShortUInt => 'B',
            /* Specs says 'U', RabbitMQ says 's' (which means ShortString in specs) */
            AMQPType::ShortInt       => 's',
            AMQPType::ShortUInt      => 'u',
            AMQPType::LongInt        => 'I',
            AMQPType::LongUInt       => 'i',
            /* RabbitMQ treats both 'l' and 'L' as LongLongInt and ignores LongLongUInt */
            AMQPType::LongLongInt    |
            AMQPType::LongLongUInt   => 'l',
            AMQPType::Float          => 'f',
            AMQPType::Double         => 'd',
            AMQPType::DecimalValue   => 'D',
            /* ShortString only exists for internal usage, we shouldn't ever have to use this */
            AMQPType::ShortString    => '_',
            AMQPType::LongString     => 'S',
            AMQPType::FieldArray     => 'A',
            AMQPType::Timestamp      => 'T',
            AMQPType::FieldTable     => 'F',
            AMQPType::ByteArray      => 'x',
            AMQPType::Void           => 'V',
        }
    }
}

impl fmt::Display for AMQPType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

/// A bool
pub type Boolean        = bool;
/// An i8
pub type ShortShortInt  = i8;
/// A u8
pub type ShortShortUInt = u8;
/// An i16
pub type ShortInt       = i16;
/// A u16
pub type ShortUInt      = u16;
/// An i32
pub type LongInt        = i32;
/// A u32
pub type LongUInt       = u32;
/// An i64
pub type LongLongInt    = i64;
/// A u64
pub type LongLongUInt   = u64;
/// A f32
pub type Float          = f32;
/// A f64
pub type Double         = f64;
/// A timestamp (u32)
pub type Timestamp      = LongLongUInt;
/// No value
pub type Void           = ();

/// A String (deprecated)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
pub struct ShortString(pub String);
/// A String
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
pub struct LongString(pub String);
/// An array of AMQPValue
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
pub struct FieldArray(pub Vec<AMQPValue>);
/// A Map<String, AMQPValue>
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
pub struct FieldTable(pub BTreeMap<ShortString, AMQPValue>);
/// An array of bytes (RabbitMQ specific)
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
pub struct ByteArray(pub Vec<u8>);

/// A Decimal value composed of a scale and a value
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
pub struct DecimalValue {
    /// The scale of the value
    pub scale: ShortShortUInt,
    /// The actual value
    pub value: LongUInt,
}

/// A Reference pointing to a ShortString
pub struct ShortStringRef<'a>(pub &'a str);
/// A Reference pointing to a LongString
pub struct LongStringRef<'a>(pub &'a str);

impl<'a> ShortString {
    /// Get a reference to a ShortString
    pub fn as_ref(&'a self) -> ShortStringRef<'a> {
        ShortStringRef(&self.0)
    }
}

impl From<&str> for ShortString {
    fn from(s: &str) -> Self {
        Self(s.to_owned())
    }
}

impl Default for ShortStringRef<'static> {
    fn default() -> Self {
        Self("")
    }
}

impl<'a> From<&'a str> for ShortStringRef<'a> {
    fn from(s: &'a str) -> Self {
        Self(s)
    }
}

impl<'a> LongString {
    /// Get a reference to a LongString
    pub fn as_ref(&'a self) -> LongStringRef<'a> {
        LongStringRef(&self.0)
    }

    /// Get a reference to a LongString as &str
    pub fn as_str(&'a self) -> &'a str {
        self.0.as_str()
    }
}

impl From<&str> for LongString {
    fn from(s: &str) -> Self {
        Self(s.to_owned())
    }
}

impl Default for LongStringRef<'static> {
    fn default() -> Self {
        Self("")
    }
}

impl<'a> From<&'a str> for LongStringRef<'a> {
    fn from(s: &'a str) -> Self {
        Self(s)
    }
}

impl From<Vec<AMQPValue>> for FieldArray {
    fn from(v: Vec<AMQPValue>) -> Self {
        Self(v)
    }
}

impl From<BTreeMap<ShortString, AMQPValue>> for FieldTable {
    fn from(m: BTreeMap<ShortString, AMQPValue>) -> Self {
        Self(m)
    }
}

impl From<Vec<u8>> for ByteArray {
    fn from(v: Vec<u8>) -> Self {
        Self(v)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_type_from_id() {
        assert_eq!(AMQPType::from_id('T'), Some(AMQPType::Timestamp));
        assert_eq!(AMQPType::from_id('S'), Some(AMQPType::LongString));
        assert_eq!(AMQPType::from_id('s'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('U'), Some(AMQPType::ShortInt));
        assert_eq!(AMQPType::from_id('l'), Some(AMQPType::LongLongInt));
        assert_eq!(AMQPType::from_id('z'), None);
    }

    #[test]
    fn test_type_get_id() {
        assert_eq!(AMQPType::LongLongInt.get_id(),  'l');
        assert_eq!(AMQPType::LongLongUInt.get_id(), 'l');
        assert_eq!(AMQPType::ShortString.get_id(),  '_');
    }

    #[test]
    fn test_type_to_string() {
        assert_eq!(AMQPType::Boolean.to_string(), "Boolean");
        assert_eq!(AMQPType::Void.to_string(),    "Void");
    }
}
<|endoftext|>


<commit_before>use relation::Change;
use flow::Flow;
use value::{Value, Field, Tuple};
use relation::Reference;

#[derive(Clone, Debug, Copy)]
pub enum Primitive {
    Add,
    Subtract,
    Count,
    Sum,
    Any
}

// TODO we hackily assign source numbers to inner and outer
//      will be fixed when Reference goes away
const OUTER: usize = 0;
const INNER: usize = 1;

impl Reference {
    pub fn resolve_as_vector<'a>(&'a self, outer: &'a Tuple, inner_fields: &[Field], inner_values: &'a [Vec<Value>]) -> Vec<&Value> {
        match *self {
            Reference::Constant{ref value} => {
                vec![value]
            },
            Reference::Variable{source, ref field} => {
                match source {
                    OUTER => {
                        vec![outer.field(field)]
                    }
                    INNER => {
                        let ix = inner_fields.iter().position(|inner_field| inner_field == field).unwrap();
                        inner_values.iter().map(|values| &values[ix]).collect()
                    }
                    _ => unreachable!(),
                }
            }
        }
    }
}

impl Primitive {
    pub fn eval_from_join<'a>(&self, arguments: &[Reference], inputs: &[Tuple]) -> Vec<Vec<Value>> {
        use primitive::Primitive::*;
        use value::Value::*;
        let values = arguments.iter().map(|reference|
            reference.resolve(&inputs[..])
            ).collect::<Vec<_>>();
        match (*self, &values[..]) {
            (Add, [&Float(a), &Float(b)]) => vec![vec![Float(a+b)]],
            (Subtract, [&Float(a), &Float(b)]) => vec![vec![Float(a-b)]],
            (Count, _) => panic!("Cannot use {:?} in a join", self),
            (Sum, _) => panic!("Cannot use {:?} in a join", self),
            (Any, _) => panic!("Cannot use {:?} in a join", self),
            _ => panic!("Type error while calling: {:?} {:?}", self, &arguments)
        }
    }

    pub fn eval_from_aggregate<'a>(&self, arguments: &[Reference], outer: &Tuple, inner_fields: &[Field], inner_values: &[Vec<Value>]) -> Vec<Vec<Value>> {
        use primitive::Primitive::*;
        use value::Value::*;
        match (*self, arguments) {
            (Add, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Subtract, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Count, [_]) => {
                vec![vec![Float(inner_values.len() as f64)]]
            }
            (Sum, [ref in_ref]) => {
                let in_values = in_ref.resolve_as_vector(outer, inner_fields, inner_values);
                let sum = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float,
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                vec![vec![Float(sum)]]
            },
            (Any, [ref in_ref]) => {
                let in_values = in_ref.resolve_as_vector(outer, inner_fields, inner_values);
                vec![vec![Bool(in_values.len() > 0)]]
            }
            _ => panic!("Wrong number of arguments while calling: {:?} {:?}", self, arguments),
        }
    }

    pub fn from_str(string: &str) -> Self {
        match string {
            "add" => Primitive::Add,
            "subtract" => Primitive::Subtract,
            "count" => Primitive::Count,
            "sum" => Primitive::Sum,
            "any" => Primitive::Any,
            _ => panic!("Unknown primitive: {:?}", string),
        }
    }
}

pub fn primitives() -> Vec<(&'static str, Vec<&'static str>, Vec<&'static str>, Vec<&'static str>)> {
    vec![
        ("add", vec!["in A", "in B"], vec![], vec!["out"]),
        ("subtract", vec!["in A", "in B"], vec![], vec!["out"]),
        ("count", vec![], vec!["in"], vec!["out"]),
        ("sum", vec![], vec!["in"], vec!["out"]),
        ("any", vec![], vec!["in"], vec!["out"]),
    ]
}

pub fn install(flow: &mut Flow) {
    let mut view_values = Vec::new();
    let mut field_values = Vec::new();
    let mut display_name_values = Vec::new();
    for (name, scalar_inputs, vector_inputs, outputs) in primitives().into_iter() {
        view_values.push(vec![string!("{}", name), string!("primitive")]);
        display_name_values.push(vec![string!("{}", name), string!("{}", name)]);
        for field in scalar_inputs.into_iter() {
            field_values.push(vec![string!("{}: {}", name, field), string!("{}", name), string!("scalar input")]);
            display_name_values.push(vec![string!("{}: {}", name, field), string!("{}", field)]);
        }
        for field in vector_inputs.into_iter() {
            field_values.push(vec![string!("{}: {}", name, field), string!("{}", name), string!("vector input")]);
            display_name_values.push(vec![string!("{}: {}", name, field), string!("{}", field)]);
        }
        for field in outputs.into_iter() {
            field_values.push(vec![string!("{}: {}", name, field), string!("{}", name), string!("output")]);
            display_name_values.push(vec![string!("{}: {}", name, field), string!("{}", field)]);
        }
    }
    flow.get_output_mut("view").change(Change{
        fields: vec!["view: view".to_owned(), "view: kind".to_owned()],
        insert: view_values,
        remove: Vec::new(),
    });
    flow.get_output_mut("field").change(Change{
        fields: vec!["field: field".to_owned(), "field: view".to_owned(), "field: kind".to_owned()],
        insert: field_values,
        remove: Vec::new(),
    });
    flow.get_output_mut("display name").change(Change{
        fields: vec!["display name: id".to_owned(), "display name: name".to_owned()],
        insert: display_name_values,
        remove: Vec::new(),
    });
}<commit_msg>Replace any by empty<commit_after>use relation::Change;
use flow::Flow;
use value::{Value, Field, Tuple};
use relation::Reference;

#[derive(Clone, Debug, Copy)]
pub enum Primitive {
    Add,
    Subtract,
    Count,
    Sum,
    Empty,
}

// TODO we hackily assign source numbers to inner and outer
//      will be fixed when Reference goes away
const OUTER: usize = 0;
const INNER: usize = 1;

impl Reference {
    pub fn resolve_as_vector<'a>(&'a self, outer: &'a Tuple, inner_fields: &[Field], inner_values: &'a [Vec<Value>]) -> Vec<&Value> {
        match *self {
            Reference::Constant{ref value} => {
                vec![value]
            },
            Reference::Variable{source, ref field} => {
                match source {
                    OUTER => {
                        vec![outer.field(field)]
                    }
                    INNER => {
                        let ix = inner_fields.iter().position(|inner_field| inner_field == field).unwrap();
                        inner_values.iter().map(|values| &values[ix]).collect()
                    }
                    _ => unreachable!(),
                }
            }
        }
    }
}

impl Primitive {
    pub fn eval_from_join<'a>(&self, arguments: &[Reference], inputs: &[Tuple]) -> Vec<Vec<Value>> {
        use primitive::Primitive::*;
        use value::Value::*;
        let values = arguments.iter().map(|reference|
            reference.resolve(&inputs[..])
            ).collect::<Vec<_>>();
        match (*self, &values[..]) {
            (Add, [&Float(a), &Float(b)]) => vec![vec![Float(a+b)]],
            (Subtract, [&Float(a), &Float(b)]) => vec![vec![Float(a-b)]],
            (Count, _) => panic!("Cannot use {:?} in a join", self),
            (Sum, _) => panic!("Cannot use {:?} in a join", self),
            (Empty, _) => panic!("Cannot use {:?} in a join", self),
            _ => panic!("Type error while calling: {:?} {:?}", self, &arguments)
        }
    }

    pub fn eval_from_aggregate<'a>(&self, arguments: &[Reference], outer: &Tuple, inner_fields: &[Field], inner_values: &[Vec<Value>]) -> Vec<Vec<Value>> {
        use primitive::Primitive::*;
        use value::Value::*;
        match (*self, arguments) {
            (Add, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Subtract, _) => panic!("Cannot use {:?} in an aggregate", self),
            (Count, [_]) => {
                vec![vec![Float(inner_values.len() as f64)]]
            }
            (Sum, [ref in_ref]) => {
                let in_values = in_ref.resolve_as_vector(outer, inner_fields, inner_values);
                let sum = in_values.iter().fold(0f64, |sum, value|
                    match **value {
                        Float(float) => sum + float,
                        _ => panic!("Type error while calling: {:?} {:?}", self, in_values),
                    });
                vec![vec![Float(sum)]]
            },
            (Empty, [ref in_ref]) => {
                let in_values = in_ref.resolve_as_vector(outer, inner_fields, inner_values);
                vec![vec![Bool(in_values.len() == 0)]]
            }
            _ => panic!("Wrong number of arguments while calling: {:?} {:?}", self, arguments),
        }
    }

    pub fn from_str(string: &str) -> Self {
        match string {
            "add" => Primitive::Add,
            "subtract" => Primitive::Subtract,
            "count" => Primitive::Count,
            "sum" => Primitive::Sum,
            "empty" => Primitive::Empty,
            _ => panic!("Unknown primitive: {:?}", string),
        }
    }
}

pub fn primitives() -> Vec<(&'static str, Vec<&'static str>, Vec<&'static str>, Vec<&'static str>)> {
    vec![
        ("add", vec!["in A", "in B"], vec![], vec!["out"]),
        ("subtract", vec!["in A", "in B"], vec![], vec!["out"]),
        ("count", vec![], vec!["in"], vec!["out"]),
        ("sum", vec![], vec!["in"], vec!["out"]),
        ("empty", vec![], vec!["in"], vec!["out"]),
    ]
}

pub fn install(flow: &mut Flow) {
    let mut view_values = Vec::new();
    let mut field_values = Vec::new();
    let mut display_name_values = Vec::new();
    for (name, scalar_inputs, vector_inputs, outputs) in primitives().into_iter() {
        view_values.push(vec![string!("{}", name), string!("primitive")]);
        display_name_values.push(vec![string!("{}", name), string!("{}", name)]);
        for field in scalar_inputs.into_iter() {
            field_values.push(vec![string!("{}: {}", name, field), string!("{}", name), string!("scalar input")]);
            display_name_values.push(vec![string!("{}: {}", name, field), string!("{}", field)]);
        }
        for field in vector_inputs.into_iter() {
            field_values.push(vec![string!("{}: {}", name, field), string!("{}", name), string!("vector input")]);
            display_name_values.push(vec![string!("{}: {}", name, field), string!("{}", field)]);
        }
        for field in outputs.into_iter() {
            field_values.push(vec![string!("{}: {}", name, field), string!("{}", name), string!("output")]);
            display_name_values.push(vec![string!("{}: {}", name, field), string!("{}", field)]);
        }
    }
    flow.get_output_mut("view").change(Change{
        fields: vec!["view: view".to_owned(), "view: kind".to_owned()],
        insert: view_values,
        remove: Vec::new(),
    });
    flow.get_output_mut("field").change(Change{
        fields: vec!["field: field".to_owned(), "field: view".to_owned(), "field: kind".to_owned()],
        insert: field_values,
        remove: Vec::new(),
    });
    flow.get_output_mut("display name").change(Change{
        fields: vec!["display name: id".to_owned(), "display name: name".to_owned()],
        insert: display_name_values,
        remove: Vec::new(),
    });
}<|endoftext|>


<commit_before>use libc;

use std::collections::HashMap;
use std::collections::hash_map;
use std::ffi::{CStr, CString};
use std::ops::Deref;
use std::ptr;

pub struct PropertyBag<'a>(HashMap<&'a CStr, &'a CStr>);

pub struct OwnedPropertyBag(HashMap<CString, CString>);

pub struct PropertyBagIter<'a>(hash_map::Iter<'a, &'a CStr, &'a CStr>);

impl<'a> PropertyBag<'a> {
    pub unsafe fn new_from_key_value_pairs(pairs: *const *const libc::c_char) -> PropertyBag<'a> {
        let mut map = HashMap::new();

        if !pairs.is_null() {
            let mut i = 0;
            loop {
                let key = *pairs.offset(i);
                if !key.is_null() {
                    let val = *pairs.offset(i + 1);
                    assert!(!val.is_null());

                    let key_str = CStr::from_ptr(key);
                    let val_str = CStr::from_ptr(val);

                    map.insert(key_str, val_str);
                } else {
                    break;
                }

                i += 2;
            }
        }

        PropertyBag(map)
    }

    pub fn from_owned(owned: &OwnedPropertyBag) -> PropertyBag {
        let mut map = HashMap::new();

        for (k, v) in &owned.0 {
            map.insert(k.deref(), v.deref());
        }

        PropertyBag(map)
    }

    pub fn to_owned(&self) -> OwnedPropertyBag {
        let mut map = HashMap::<CString, CString>::new();

        for (k, v) in &self.0 {
            map.insert((*k).to_owned(), (*v).to_owned());
        }

        OwnedPropertyBag(map)
    }

    pub fn ffi(&self) -> *const PropertyBag {
        self as *const PropertyBag
    }

    pub fn len(&self) -> usize {
        self.0.len()
    }

    pub fn lookup_cstr(&self, key: &CStr) -> Option<&CStr> {
        self.0.get(key).map(|v| *v)
    }

    pub fn lookup(&self, key: &str) -> Option<&str> {
        let k = CString::new(key).unwrap();
        self.lookup_cstr(&k).map(|v| v.to_str().unwrap())
    }

    pub fn enumerate(&self,
                 enum_fn: fn (key: *const libc::c_char, val: *const libc::c_char, data: *const libc::c_void),
                 data: *const libc::c_void) {
        for (k, v) in &self.0 {
            enum_fn(k.as_ptr(), v.as_ptr(), data);
        }
    }

    pub fn iter(&self) -> PropertyBagIter {
        PropertyBagIter(self.0.iter())
    }
}

impl<'a> Iterator for PropertyBagIter<'a> {
    type Item = (&'a str, &'a str);

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|(k, v)| (k.to_str().unwrap(), v.to_str().unwrap()))
    }
}

#[no_mangle]
pub extern fn rsvg_property_bag_new<'a>(atts: *const *const libc::c_char) -> *const PropertyBag<'a> {
    let pbag = unsafe { PropertyBag::new_from_key_value_pairs(atts) };
    Box::into_raw(Box::new(pbag))
}

#[no_mangle]
pub extern fn rsvg_property_bag_free(pbag: *mut PropertyBag) {
    unsafe {
        let _ = Box::from_raw(pbag);
    }
}

#[no_mangle]
pub extern fn rsvg_property_bag_size(pbag: *const PropertyBag) -> libc::c_uint {
    unsafe {
        let pbag = &*pbag;

        pbag.len() as libc::c_uint
    }
}

#[no_mangle]
pub extern fn rsvg_property_bag_enumerate(pbag: *const PropertyBag,
                                          enum_fn: fn (key: *const libc::c_char, val: *const libc::c_char, data: *const libc::c_void),
                                          data: *const libc::c_void) {
    unsafe {
        let pbag = &*pbag;

        pbag.enumerate(enum_fn, data);
    }
}

#[no_mangle]
pub extern fn rsvg_property_bag_lookup(pbag: *const PropertyBag,
                                       raw_key: *const libc::c_char) -> *const libc::c_char {
    unsafe {
        let pbag = &*pbag;
        let key = CStr::from_ptr(raw_key);
        match pbag.lookup_cstr(key) {
            Some(v) => v.as_ptr(),
            None => ptr::null()
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::ffi::CString;

    #[test]
    fn empty_property_bag() {
        let map = unsafe { PropertyBag::new_from_key_value_pairs(ptr::null()) };
        assert_eq!(map.len(), 0);
    }

    #[test]
    fn property_bag_lookups_and_iters() {
        let pairs = [
            CString::new("alpha").unwrap(),
            CString::new("1").unwrap(),
            CString::new("beta").unwrap(),
            CString::new("2").unwrap(),
        ];

        let mut v = Vec::new();

        for x in &pairs {
            v.push(x.as_ptr() as *const libc::c_char);
        }

        v.push(ptr::null());

        let pbag = unsafe { PropertyBag::new_from_key_value_pairs(v.as_ptr()) };

        assert_eq!(pbag.lookup("alpha"), Some("1"));
        assert_eq!(pbag.lookup("beta"), Some("2"));
        assert_eq!(pbag.lookup("gamma"), None);

        let mut had_alpha: bool = false;
        let mut had_beta: bool = false;

        for (k, _) in pbag.iter() {
            if k == "alpha" {
                had_alpha = true;
            } else if k == "beta" {
                had_beta = true;
            }
        }

        assert!(had_alpha);
        assert!(had_beta);
    }
}
<commit_msg>PropertyBag: Add an iter_cstr() that outputs &CStr, instead of &str<commit_after>use libc;

use std::collections::HashMap;
use std::collections::hash_map;
use std::ffi::{CStr, CString};
use std::ops::Deref;
use std::ptr;

pub struct PropertyBag<'a>(HashMap<&'a CStr, &'a CStr>);

pub struct OwnedPropertyBag(HashMap<CString, CString>);

pub struct PropertyBagIter<'a>(hash_map::Iter<'a, &'a CStr, &'a CStr>);

pub struct PropertyBagCStrIter<'a>(hash_map::Iter<'a, &'a CStr, &'a CStr>);

impl<'a> PropertyBag<'a> {
    pub unsafe fn new_from_key_value_pairs(pairs: *const *const libc::c_char) -> PropertyBag<'a> {
        let mut map = HashMap::new();

        if !pairs.is_null() {
            let mut i = 0;
            loop {
                let key = *pairs.offset(i);
                if !key.is_null() {
                    let val = *pairs.offset(i + 1);
                    assert!(!val.is_null());

                    let key_str = CStr::from_ptr(key);
                    let val_str = CStr::from_ptr(val);

                    map.insert(key_str, val_str);
                } else {
                    break;
                }

                i += 2;
            }
        }

        PropertyBag(map)
    }

    pub fn from_owned(owned: &OwnedPropertyBag) -> PropertyBag {
        let mut map = HashMap::new();

        for (k, v) in &owned.0 {
            map.insert(k.deref(), v.deref());
        }

        PropertyBag(map)
    }

    pub fn to_owned(&self) -> OwnedPropertyBag {
        let mut map = HashMap::<CString, CString>::new();

        for (k, v) in &self.0 {
            map.insert((*k).to_owned(), (*v).to_owned());
        }

        OwnedPropertyBag(map)
    }

    pub fn ffi(&self) -> *const PropertyBag {
        self as *const PropertyBag
    }

    pub fn len(&self) -> usize {
        self.0.len()
    }

    pub fn lookup_cstr(&self, key: &CStr) -> Option<&CStr> {
        self.0.get(key).map(|v| *v)
    }

    pub fn lookup(&self, key: &str) -> Option<&str> {
        let k = CString::new(key).unwrap();
        self.lookup_cstr(&k).map(|v| v.to_str().unwrap())
    }

    pub fn enumerate(&self,
                 enum_fn: fn (key: *const libc::c_char, val: *const libc::c_char, data: *const libc::c_void),
                 data: *const libc::c_void) {
        for (k, v) in &self.0 {
            enum_fn(k.as_ptr(), v.as_ptr(), data);
        }
    }

    pub fn iter(&self) -> PropertyBagIter {
        PropertyBagIter(self.0.iter())
    }

    pub fn cstr_iter(&self) -> PropertyBagCStrIter {
        PropertyBagCStrIter(self.0.iter())
    }
}

impl<'a> Iterator for PropertyBagIter<'a> {
    type Item = (&'a str, &'a str);

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|(k, v)| (k.to_str().unwrap(), v.to_str().unwrap()))
    }
}

impl<'a> Iterator for PropertyBagCStrIter<'a> {
    type Item = (&'a CStr, &'a CStr);

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|(k, v)| (*k, *v))
    }
}

#[no_mangle]
pub extern fn rsvg_property_bag_new<'a>(atts: *const *const libc::c_char) -> *const PropertyBag<'a> {
    let pbag = unsafe { PropertyBag::new_from_key_value_pairs(atts) };
    Box::into_raw(Box::new(pbag))
}

#[no_mangle]
pub extern fn rsvg_property_bag_free(pbag: *mut PropertyBag) {
    unsafe {
        let _ = Box::from_raw(pbag);
    }
}

#[no_mangle]
pub extern fn rsvg_property_bag_size(pbag: *const PropertyBag) -> libc::c_uint {
    unsafe {
        let pbag = &*pbag;

        pbag.len() as libc::c_uint
    }
}

#[no_mangle]
pub extern fn rsvg_property_bag_enumerate(pbag: *const PropertyBag,
                                          enum_fn: fn (key: *const libc::c_char, val: *const libc::c_char, data: *const libc::c_void),
                                          data: *const libc::c_void) {
    unsafe {
        let pbag = &*pbag;

        pbag.enumerate(enum_fn, data);
    }
}

#[no_mangle]
pub extern fn rsvg_property_bag_lookup(pbag: *const PropertyBag,
                                       raw_key: *const libc::c_char) -> *const libc::c_char {
    unsafe {
        let pbag = &*pbag;
        let key = CStr::from_ptr(raw_key);
        match pbag.lookup_cstr(key) {
            Some(v) => v.as_ptr(),
            None => ptr::null()
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::ffi::CString;

    #[test]
    fn empty_property_bag() {
        let map = unsafe { PropertyBag::new_from_key_value_pairs(ptr::null()) };
        assert_eq!(map.len(), 0);
    }

    #[test]
    fn property_bag_lookups_and_iters() {
        let pairs = [
            CString::new("alpha").unwrap(),
            CString::new("1").unwrap(),
            CString::new("beta").unwrap(),
            CString::new("2").unwrap(),
        ];

        let mut v = Vec::new();

        for x in &pairs {
            v.push(x.as_ptr() as *const libc::c_char);
        }

        v.push(ptr::null());

        let pbag = unsafe { PropertyBag::new_from_key_value_pairs(v.as_ptr()) };

        assert_eq!(pbag.lookup("alpha"), Some("1"));
        assert_eq!(pbag.lookup("beta"), Some("2"));
        assert_eq!(pbag.lookup("gamma"), None);

        let mut had_alpha: bool = false;
        let mut had_beta: bool = false;

        for (k, _) in pbag.iter() {
            if k == "alpha" {
                had_alpha = true;
            } else if k == "beta" {
                had_beta = true;
            }
        }

        assert!(had_alpha);
        assert!(had_beta);
    }
}
<|endoftext|>


<commit_before>mod date_and_time;
mod ops;

use schema::{connection, DropTable, NewUser, TestBackend};
use schema::users::dsl::*;
use diesel::*;
use diesel::backend::Backend;
use diesel::query_builder::*;
use diesel::dsl::*;

#[test]
fn test_count_counts_the_rows() {
    let connection = connection();
    let source = users.select(count(id));

    assert_eq!(Ok(0), source.first(&connection));
    insert_into(users)
        .values(&NewUser::new("Sean", None))
        .execute(&connection)
        .unwrap();
    assert_eq!(Ok(1), source.first(&connection));
}

#[test]
fn test_count_star() {
    let connection = connection();
    let source = users.count();

    assert_eq!(Ok(0), source.first(&connection));
    insert_into(users)
        .values(&NewUser::new("Sean", None))
        .execute(&connection)
        .unwrap();
    assert_eq!(Ok(1), source.first(&connection));

    // Ensure we're doing COUNT(*) instead of COUNT(table.*) which is going to be more efficient
    assert!(
        debug_query::<TestBackend, _>(&source)
            .to_string()
            .starts_with("SELECT COUNT(*) FROM")
    );
}

table! {
    numbers (n) {
        n -> Integer,
    }
}

#[test]
fn test_count_max() {
    use self::numbers::columns::*;
    use self::numbers::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO numbers (n) VALUES (2), (1), (5)")
        .unwrap();
    let source = numbers.select(max(n));

    assert_eq!(Ok(Some(5)), source.first(&connection));
    connection
        .execute("DELETE FROM numbers WHERE n = 5")
        .unwrap();
    assert_eq!(Ok(Some(2)), source.first(&connection));
    connection.execute("DELETE FROM numbers").unwrap();
    assert_eq!(Ok(None::<i32>), source.first(&connection));
}

#[cfg(feature = "postgres")]
table! {
    number_arrays (na) {
        na -> Array<Integer>,
    }
}

#[test]
#[cfg(feature = "postgres")]
fn test_min_max_of_array() {
    use self::number_arrays::dsl::*;

    let connection = connection();
    connection
        .execute("CREATE TABLE number_arrays ( na INTEGER[] PRIMARY KEY )")
        .unwrap();
    let _bomb = DropTable {
        connection: &connection,
        table_name: "number_arrays",
    };

    insert_into(number_arrays)
        .values(&vec![
            na.eq(vec![1, 1, 100]),
            na.eq(vec![1, 5, 5]),
            na.eq(vec![5, 0]),
        ])
        .execute(&connection)
        .unwrap();

    let max_query = number_arrays.select(max(na));
    let min_query = number_arrays.select(min(na));
    assert_eq!(Ok(Some(vec![5, 0])), max_query.first(&connection));
    assert_eq!(Ok(Some(vec![1, 1, 100])), min_query.first(&connection));

    delete(number_arrays.filter(na.eq(vec![5, 0])))
        .execute(&connection)
        .unwrap();
    assert_eq!(Ok(Some(vec![1, 5, 5])), max_query.first(&connection));
    assert_eq!(Ok(Some(vec![1, 1, 100])), min_query.first(&connection));

    delete(number_arrays.filter(na.eq(vec![1, 1, 100])))
        .execute(&connection)
        .unwrap();
    assert_eq!(Ok(Some(vec![1, 5, 5])), max_query.first(&connection));
    assert_eq!(Ok(Some(vec![1, 5, 5])), min_query.first(&connection));

    delete(number_arrays).execute(&connection).unwrap();
    assert_eq!(Ok(None::<Vec<i32>>), max_query.first(&connection));
    assert_eq!(Ok(None::<Vec<i32>>), min_query.first(&connection));
}

#[test]
fn max_returns_same_type_as_expression_being_maximized() {
    let connection = connection();
    let source = users.select(max(name));

    let data: &[_] = &[
        NewUser::new("B", None),
        NewUser::new("C", None),
        NewUser::new("A", None),
    ];
    insert_into(users)
        .values(data)
        .execute(&connection)
        .unwrap();
    assert_eq!(Ok(Some("C".to_string())), source.first(&connection));
    connection
        .execute("DELETE FROM users WHERE name = 'C'")
        .unwrap();
    assert_eq!(Ok(Some("B".to_string())), source.first(&connection));
    connection.execute("DELETE FROM users").unwrap();
    assert_eq!(Ok(None::<String>), source.first(&connection));
}

use std::marker::PhantomData;

struct Arbitrary<T> {
    _marker: PhantomData<T>,
}

impl<T> Expression for Arbitrary<T> {
    type SqlType = T;
}

impl<T, DB> QueryFragment<DB> for Arbitrary<T>
where
    DB: Backend,
{
    fn walk_ast(&self, _: AstPass<DB>) -> QueryResult<()> {
        Ok(())
    }
}

impl<T, QS> SelectableExpression<QS> for Arbitrary<T> {}

impl<T, QS> AppearsOnTable<QS> for Arbitrary<T> {}

fn arbitrary<T>() -> Arbitrary<T> {
    Arbitrary {
        _marker: PhantomData,
    }
}

#[test]
fn max_accepts_all_numeric_string_and_date_types() {
    let _ = users.select(max(arbitrary::<sql_types::SmallInt>()));
    let _ = users.select(max(arbitrary::<sql_types::Integer>()));
    let _ = users.select(max(arbitrary::<sql_types::BigInt>()));
    let _ = users.select(max(arbitrary::<sql_types::Float>()));
    let _ = users.select(max(arbitrary::<sql_types::Double>()));

    let _ = users.select(max(arbitrary::<sql_types::VarChar>()));
    let _ = users.select(max(arbitrary::<sql_types::Text>()));

    let _ = users.select(max(arbitrary::<sql_types::Nullable<sql_types::SmallInt>>()));
    let _ = users.select(max(arbitrary::<sql_types::Nullable<sql_types::Integer>>()));
    let _ = users.select(max(arbitrary::<sql_types::Nullable<sql_types::BigInt>>()));
    let _ = users.select(max(arbitrary::<sql_types::Nullable<sql_types::Float>>()));
    let _ = users.select(max(arbitrary::<sql_types::Nullable<sql_types::Double>>()));

    let _ = users.select(max(arbitrary::<sql_types::Nullable<sql_types::VarChar>>()));
    let _ = users.select(max(arbitrary::<sql_types::Nullable<sql_types::Text>>()));
}

#[test]
fn test_min() {
    use self::numbers::columns::*;
    use self::numbers::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO numbers (n) VALUES (2), (1), (5)")
        .unwrap();
    let source = numbers.select(min(n));

    assert_eq!(Ok(Some(1)), source.first(&connection));
    connection
        .execute("DELETE FROM numbers WHERE n = 1")
        .unwrap();
    assert_eq!(Ok(Some(2)), source.first(&connection));
    connection.execute("DELETE FROM numbers").unwrap();
    assert_eq!(Ok(None::<i32>), source.first(&connection));
}

sql_function!(coalesce, coalesce_t, (x: sql_types::Nullable<sql_types::VarChar>, y: sql_types::VarChar) -> sql_types::VarChar);

#[test]
fn function_with_multiple_arguments() {
    use schema::users::dsl::*;

    let connection = connection();
    let new_users = vec![
        NewUser::new("Sean", Some("black")),
        NewUser::new("Tess", None),
    ];
    insert_into(users)
        .values(&new_users)
        .execute(&connection)
        .unwrap();

    let expected_data = vec!["black".to_string(), "Tess".to_string()];
    let data = users
        .select(coalesce(hair_color, name))
        .load::<String>(&connection);

    assert_eq!(Ok(expected_data), data);
}

#[test]
fn test_sum() {
    use self::numbers::columns::*;
    use self::numbers::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO numbers (n) VALUES (2), (1), (5)")
        .unwrap();
    let source = numbers.select(sum(n));

    assert_eq!(Ok(Some(8)), source.first(&connection));
    connection
        .execute("DELETE FROM numbers WHERE n = 2")
        .unwrap();
    assert_eq!(Ok(Some(6)), source.first(&connection));
    connection.execute("DELETE FROM numbers").unwrap();
    assert_eq!(Ok(None::<i64>), source.first(&connection));
}

table! {
    precision_numbers (n) {
        n -> Double,
    }
}

#[test]
fn test_sum_for_double() {
    use self::precision_numbers::columns::*;
    use self::precision_numbers::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO precision_numbers (n) VALUES (2), (1), (5.5)")
        .unwrap();
    let source = numbers.select(sum(n));

    assert_eq!(Ok(Some(8.5f64)), source.first(&connection));
    connection
        .execute("DELETE FROM precision_numbers WHERE n = 2")
        .unwrap();
    assert_eq!(Ok(Some(6.5f64)), source.first(&connection));
    connection.execute("DELETE FROM precision_numbers").unwrap();
    assert_eq!(Ok(None::<f64>), source.first(&connection));
}

table! {
    nullable_doubles {
        id -> Integer,
        n -> Nullable<Double>,
    }
}

#[test]
fn test_sum_for_nullable() {
    use self::nullable_doubles::columns::*;
    use self::nullable_doubles::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO nullable_doubles (n) VALUES (null), (null), (5.5)")
        .unwrap();
    let source = numbers.select(sum(n));

    assert_eq!(Ok(Some(5.5f64)), source.first(&connection));
    connection
        .execute("DELETE FROM nullable_doubles WHERE n = 5.5")
        .unwrap();
    assert_eq!(Ok(None), source.first::<Option<f64>>(&connection));
}

#[test]
fn test_avg() {
    use self::precision_numbers::columns::*;
    use self::precision_numbers::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO precision_numbers (n) VALUES (2), (1), (6)")
        .unwrap();
    let source = numbers.select(avg(n));

    assert_eq!(Ok(Some(3f64)), source.first(&connection));
    connection
        .execute("DELETE FROM precision_numbers WHERE n = 2")
        .unwrap();
    assert_eq!(Ok(Some(3.5f64)), source.first(&connection));
    connection.execute("DELETE FROM precision_numbers").unwrap();
    assert_eq!(Ok(None::<f64>), source.first(&connection));
}

#[test]
fn test_avg_for_nullable() {
    use self::nullable_doubles::columns::*;
    use self::nullable_doubles::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO nullable_doubles (n) VALUES (null), (null), (6)")
        .unwrap();
    let source = numbers.select(avg(n));

    assert_eq!(Ok(Some(6f64)), source.first(&connection));
    connection
        .execute("DELETE FROM nullable_doubles WHERE n = 6")
        .unwrap();
    assert_eq!(Ok(None), source.first::<Option<f64>>(&connection));
}

#[test]
#[cfg(feature = "postgres")] // FIXME: We need to test this on SQLite when we support these types
fn test_avg_for_integer() {
    use self::numbers::columns::*;
    use self::numbers::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO numbers (n) VALUES (2), (1), (6)")
        .unwrap();
    let source = numbers.select(avg(n));

    let result = source.first(&connection);
    let expected_result = data_types::PgNumeric::Positive {
        digits: vec![3],
        weight: 0,
        scale: 16,
    };
    assert_eq!(Ok(Some(expected_result)), result);

    connection
        .execute("DELETE FROM numbers WHERE n = 2")
        .unwrap();
    let result = source.first(&connection);
    let expected_result = data_types::PgNumeric::Positive {
        digits: vec![3, 5000],
        weight: 0,
        scale: 16,
    };
    assert_eq!(Ok(Some(expected_result)), result);
}

table! {
    numeric (n) {
        n -> Numeric,
    }
}

#[test]
#[cfg(feature = "postgres")] // FIXME: We need to test this on MySQL
fn test_avg_for_numeric() {
    use self::numeric::columns::*;
    use self::numeric::table as numeric;

    let connection = connection();
    connection
        .execute("CREATE TABLE numeric (n NUMERIC(8,2))")
        .unwrap();
    connection
        .execute("INSERT INTO numeric (n) VALUES (2), (1), (6)")
        .unwrap();
    let source = numeric.select(avg(n));

    let result = source.first(&connection);
    let expected_result = data_types::PgNumeric::Positive {
        digits: vec![3],
        weight: 0,
        scale: 16,
    };
    assert_eq!(Ok(Some(expected_result)), result);
}

#[test]
#[cfg(feature = "postgres")]
fn test_arrays_a() {
    let connection = connection();

    use diesel::types::Int4;
    let value = select(array::<Int4, _>((1, 2)))
        .get_result::<Vec<i32>>(&connection)
        .unwrap();

    assert_eq!(value, vec![1, 2]);
}

#[test]
#[cfg(feature = "postgres")]
fn test_arrays_b() {
    use diesel::types::{Array, Int4};
    sql_function!(unnest, unnest_t, (a: Array<Int4>) -> Int4);

    use self::numbers::columns::*;
    use self::numbers::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO numbers (n) VALUES (7)")
        .unwrap();

    let value = numbers
        .select(unnest(array((n, n + n))))
        .load::<i32>(&connection)
        .unwrap();

    assert_eq!(value, vec![7, 14]);
}
<commit_msg>Fix broken build<commit_after>mod date_and_time;
mod ops;

use schema::{connection, DropTable, NewUser, TestBackend};
use schema::users::dsl::*;
use diesel::*;
use diesel::backend::Backend;
use diesel::query_builder::*;
use diesel::dsl::*;

#[test]
fn test_count_counts_the_rows() {
    let connection = connection();
    let source = users.select(count(id));

    assert_eq!(Ok(0), source.first(&connection));
    insert_into(users)
        .values(&NewUser::new("Sean", None))
        .execute(&connection)
        .unwrap();
    assert_eq!(Ok(1), source.first(&connection));
}

#[test]
fn test_count_star() {
    let connection = connection();
    let source = users.count();

    assert_eq!(Ok(0), source.first(&connection));
    insert_into(users)
        .values(&NewUser::new("Sean", None))
        .execute(&connection)
        .unwrap();
    assert_eq!(Ok(1), source.first(&connection));

    // Ensure we're doing COUNT(*) instead of COUNT(table.*) which is going to be more efficient
    assert!(
        debug_query::<TestBackend, _>(&source)
            .to_string()
            .starts_with("SELECT COUNT(*) FROM")
    );
}

table! {
    numbers (n) {
        n -> Integer,
    }
}

#[test]
fn test_count_max() {
    use self::numbers::columns::*;
    use self::numbers::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO numbers (n) VALUES (2), (1), (5)")
        .unwrap();
    let source = numbers.select(max(n));

    assert_eq!(Ok(Some(5)), source.first(&connection));
    connection
        .execute("DELETE FROM numbers WHERE n = 5")
        .unwrap();
    assert_eq!(Ok(Some(2)), source.first(&connection));
    connection.execute("DELETE FROM numbers").unwrap();
    assert_eq!(Ok(None::<i32>), source.first(&connection));
}

#[cfg(feature = "postgres")]
table! {
    number_arrays (na) {
        na -> Array<Integer>,
    }
}

#[test]
#[cfg(feature = "postgres")]
fn test_min_max_of_array() {
    use self::number_arrays::dsl::*;

    let connection = connection();
    connection
        .execute("CREATE TABLE number_arrays ( na INTEGER[] PRIMARY KEY )")
        .unwrap();
    let _bomb = DropTable {
        connection: &connection,
        table_name: "number_arrays",
    };

    insert_into(number_arrays)
        .values(&vec![
            na.eq(vec![1, 1, 100]),
            na.eq(vec![1, 5, 5]),
            na.eq(vec![5, 0]),
        ])
        .execute(&connection)
        .unwrap();

    let max_query = number_arrays.select(max(na));
    let min_query = number_arrays.select(min(na));
    assert_eq!(Ok(Some(vec![5, 0])), max_query.first(&connection));
    assert_eq!(Ok(Some(vec![1, 1, 100])), min_query.first(&connection));

    delete(number_arrays.filter(na.eq(vec![5, 0])))
        .execute(&connection)
        .unwrap();
    assert_eq!(Ok(Some(vec![1, 5, 5])), max_query.first(&connection));
    assert_eq!(Ok(Some(vec![1, 1, 100])), min_query.first(&connection));

    delete(number_arrays.filter(na.eq(vec![1, 1, 100])))
        .execute(&connection)
        .unwrap();
    assert_eq!(Ok(Some(vec![1, 5, 5])), max_query.first(&connection));
    assert_eq!(Ok(Some(vec![1, 5, 5])), min_query.first(&connection));

    delete(number_arrays).execute(&connection).unwrap();
    assert_eq!(Ok(None::<Vec<i32>>), max_query.first(&connection));
    assert_eq!(Ok(None::<Vec<i32>>), min_query.first(&connection));
}

#[test]
fn max_returns_same_type_as_expression_being_maximized() {
    let connection = connection();
    let source = users.select(max(name));

    let data: &[_] = &[
        NewUser::new("B", None),
        NewUser::new("C", None),
        NewUser::new("A", None),
    ];
    insert_into(users)
        .values(data)
        .execute(&connection)
        .unwrap();
    assert_eq!(Ok(Some("C".to_string())), source.first(&connection));
    connection
        .execute("DELETE FROM users WHERE name = 'C'")
        .unwrap();
    assert_eq!(Ok(Some("B".to_string())), source.first(&connection));
    connection.execute("DELETE FROM users").unwrap();
    assert_eq!(Ok(None::<String>), source.first(&connection));
}

use std::marker::PhantomData;

struct Arbitrary<T> {
    _marker: PhantomData<T>,
}

impl<T> Expression for Arbitrary<T> {
    type SqlType = T;
}

impl<T, DB> QueryFragment<DB> for Arbitrary<T>
where
    DB: Backend,
{
    fn walk_ast(&self, _: AstPass<DB>) -> QueryResult<()> {
        Ok(())
    }
}

impl<T, QS> SelectableExpression<QS> for Arbitrary<T> {}

impl<T, QS> AppearsOnTable<QS> for Arbitrary<T> {}

fn arbitrary<T>() -> Arbitrary<T> {
    Arbitrary {
        _marker: PhantomData,
    }
}

#[test]
fn max_accepts_all_numeric_string_and_date_types() {
    let _ = users.select(max(arbitrary::<sql_types::SmallInt>()));
    let _ = users.select(max(arbitrary::<sql_types::Integer>()));
    let _ = users.select(max(arbitrary::<sql_types::BigInt>()));
    let _ = users.select(max(arbitrary::<sql_types::Float>()));
    let _ = users.select(max(arbitrary::<sql_types::Double>()));

    let _ = users.select(max(arbitrary::<sql_types::VarChar>()));
    let _ = users.select(max(arbitrary::<sql_types::Text>()));

    let _ = users.select(max(arbitrary::<sql_types::Nullable<sql_types::SmallInt>>()));
    let _ = users.select(max(arbitrary::<sql_types::Nullable<sql_types::Integer>>()));
    let _ = users.select(max(arbitrary::<sql_types::Nullable<sql_types::BigInt>>()));
    let _ = users.select(max(arbitrary::<sql_types::Nullable<sql_types::Float>>()));
    let _ = users.select(max(arbitrary::<sql_types::Nullable<sql_types::Double>>()));

    let _ = users.select(max(arbitrary::<sql_types::Nullable<sql_types::VarChar>>()));
    let _ = users.select(max(arbitrary::<sql_types::Nullable<sql_types::Text>>()));
}

#[test]
fn test_min() {
    use self::numbers::columns::*;
    use self::numbers::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO numbers (n) VALUES (2), (1), (5)")
        .unwrap();
    let source = numbers.select(min(n));

    assert_eq!(Ok(Some(1)), source.first(&connection));
    connection
        .execute("DELETE FROM numbers WHERE n = 1")
        .unwrap();
    assert_eq!(Ok(Some(2)), source.first(&connection));
    connection.execute("DELETE FROM numbers").unwrap();
    assert_eq!(Ok(None::<i32>), source.first(&connection));
}

sql_function!(coalesce, coalesce_t, (x: sql_types::Nullable<sql_types::VarChar>, y: sql_types::VarChar) -> sql_types::VarChar);

#[test]
fn function_with_multiple_arguments() {
    use schema::users::dsl::*;

    let connection = connection();
    let new_users = vec![
        NewUser::new("Sean", Some("black")),
        NewUser::new("Tess", None),
    ];
    insert_into(users)
        .values(&new_users)
        .execute(&connection)
        .unwrap();

    let expected_data = vec!["black".to_string(), "Tess".to_string()];
    let data = users
        .select(coalesce(hair_color, name))
        .load::<String>(&connection);

    assert_eq!(Ok(expected_data), data);
}

#[test]
fn test_sum() {
    use self::numbers::columns::*;
    use self::numbers::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO numbers (n) VALUES (2), (1), (5)")
        .unwrap();
    let source = numbers.select(sum(n));

    assert_eq!(Ok(Some(8)), source.first(&connection));
    connection
        .execute("DELETE FROM numbers WHERE n = 2")
        .unwrap();
    assert_eq!(Ok(Some(6)), source.first(&connection));
    connection.execute("DELETE FROM numbers").unwrap();
    assert_eq!(Ok(None::<i64>), source.first(&connection));
}

table! {
    precision_numbers (n) {
        n -> Double,
    }
}

#[test]
fn test_sum_for_double() {
    use self::precision_numbers::columns::*;
    use self::precision_numbers::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO precision_numbers (n) VALUES (2), (1), (5.5)")
        .unwrap();
    let source = numbers.select(sum(n));

    assert_eq!(Ok(Some(8.5f64)), source.first(&connection));
    connection
        .execute("DELETE FROM precision_numbers WHERE n = 2")
        .unwrap();
    assert_eq!(Ok(Some(6.5f64)), source.first(&connection));
    connection.execute("DELETE FROM precision_numbers").unwrap();
    assert_eq!(Ok(None::<f64>), source.first(&connection));
}

table! {
    nullable_doubles {
        id -> Integer,
        n -> Nullable<Double>,
    }
}

#[test]
fn test_sum_for_nullable() {
    use self::nullable_doubles::columns::*;
    use self::nullable_doubles::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO nullable_doubles (n) VALUES (null), (null), (5.5)")
        .unwrap();
    let source = numbers.select(sum(n));

    assert_eq!(Ok(Some(5.5f64)), source.first(&connection));
    connection
        .execute("DELETE FROM nullable_doubles WHERE n = 5.5")
        .unwrap();
    assert_eq!(Ok(None), source.first::<Option<f64>>(&connection));
}

#[test]
fn test_avg() {
    use self::precision_numbers::columns::*;
    use self::precision_numbers::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO precision_numbers (n) VALUES (2), (1), (6)")
        .unwrap();
    let source = numbers.select(avg(n));

    assert_eq!(Ok(Some(3f64)), source.first(&connection));
    connection
        .execute("DELETE FROM precision_numbers WHERE n = 2")
        .unwrap();
    assert_eq!(Ok(Some(3.5f64)), source.first(&connection));
    connection.execute("DELETE FROM precision_numbers").unwrap();
    assert_eq!(Ok(None::<f64>), source.first(&connection));
}

#[test]
fn test_avg_for_nullable() {
    use self::nullable_doubles::columns::*;
    use self::nullable_doubles::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO nullable_doubles (n) VALUES (null), (null), (6)")
        .unwrap();
    let source = numbers.select(avg(n));

    assert_eq!(Ok(Some(6f64)), source.first(&connection));
    connection
        .execute("DELETE FROM nullable_doubles WHERE n = 6")
        .unwrap();
    assert_eq!(Ok(None), source.first::<Option<f64>>(&connection));
}

#[test]
#[cfg(feature = "postgres")] // FIXME: We need to test this on SQLite when we support these types
fn test_avg_for_integer() {
    use self::numbers::columns::*;
    use self::numbers::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO numbers (n) VALUES (2), (1), (6)")
        .unwrap();
    let source = numbers.select(avg(n));

    let result = source.first(&connection);
    let expected_result = data_types::PgNumeric::Positive {
        digits: vec![3],
        weight: 0,
        scale: 16,
    };
    assert_eq!(Ok(Some(expected_result)), result);

    connection
        .execute("DELETE FROM numbers WHERE n = 2")
        .unwrap();
    let result = source.first(&connection);
    let expected_result = data_types::PgNumeric::Positive {
        digits: vec![3, 5000],
        weight: 0,
        scale: 16,
    };
    assert_eq!(Ok(Some(expected_result)), result);
}

table! {
    numeric (n) {
        n -> Numeric,
    }
}

#[test]
#[cfg(feature = "postgres")] // FIXME: We need to test this on MySQL
fn test_avg_for_numeric() {
    use self::numeric::columns::*;
    use self::numeric::table as numeric;

    let connection = connection();
    connection
        .execute("CREATE TABLE numeric (n NUMERIC(8,2))")
        .unwrap();
    connection
        .execute("INSERT INTO numeric (n) VALUES (2), (1), (6)")
        .unwrap();
    let source = numeric.select(avg(n));

    let result = source.first(&connection);
    let expected_result = data_types::PgNumeric::Positive {
        digits: vec![3],
        weight: 0,
        scale: 16,
    };
    assert_eq!(Ok(Some(expected_result)), result);
}

#[test]
#[cfg(feature = "postgres")]
fn test_arrays_a() {
    let connection = connection();

    use diesel::sql_types::Int4;
    let value = select(array::<Int4, _>((1, 2)))
        .get_result::<Vec<i32>>(&connection)
        .unwrap();

    assert_eq!(value, vec![1, 2]);
}

#[test]
#[cfg(feature = "postgres")]
fn test_arrays_b() {
    use diesel::sql_types::{Array, Int4};
    sql_function!(unnest, unnest_t, (a: Array<Int4>) -> Int4);

    use self::numbers::columns::*;
    use self::numbers::table as numbers;

    let connection = connection();
    connection
        .execute("INSERT INTO numbers (n) VALUES (7)")
        .unwrap();

    let value = numbers
        .select(unnest(array((n, n + n))))
        .load::<i32>(&connection)
        .unwrap();

    assert_eq!(value, vec![7, 14]);
}
<|endoftext|>


<commit_before>#![crate_type = "proc-macro"]
#![recursion_limit = "192"]
#![feature(trace_macros)]
#![feature(log_syntax)]

extern crate syn;
extern crate proc_macro;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;

enum Kind {
    Module,
    Parameter,
    ModIntf,
}

#[proc_macro_derive(ModParse, attributes(ignore))]
pub fn parse(input: TokenStream) -> TokenStream {
    let source = input.to_string();
    let mut ast = syn::parse_derive_input(&source).expect("failed to parse rust syntax");
    let gen = impl_parse(&mut ast);
    gen.parse().expect("failed to serialize into rust syntax")
}
fn is_type(ty: &syn::Ty, name: &'static str) -> bool {
    if let syn::Ty::Path(_, ref path) = *ty {
        if path.segments.iter().any(|seg| seg.ident.as_ref() == name) {
            true
        } else {
            false
        }
    } else {
        false
    }
}

fn option_type(ty: &syn::Ty) -> &syn::Ty {
    if let syn::Ty::Path(_, ref path) = *ty {
        if let Some(seg) = path.segments
               .iter()
               .find(|seg| seg.ident.as_ref() == "Option") {
            if let syn::PathParameters::AngleBracketed(ref data) = seg.parameters {
                // assume simple nesting for now
                &data.types[0]
            } else {
                panic!("can't parse Option segment parameters {:?}", seg.parameters);
            }
        } else {
            panic!("Option not found!")
        }
    } else {
        panic!("not path")
    }
}

fn get_type(ty: &syn::Ty) -> Kind {
    if is_type(&ty, "Option") {
        get_type(option_type(ty))
    } else if is_type(&ty, "Module") {
        Kind::Module
    } else if is_type(&ty, "Parameter") {
        Kind::Parameter
    } else {
        Kind::ModIntf
    }
}

fn impl_parse(ast: &mut syn::DeriveInput) -> quote::Tokens {
    use syn::{Body, VariantData};

    let ref mut variants = match ast.body {
        Body::Struct(VariantData::Struct(ref vars)) => vars,
        _ => panic!("#[derive(Parse)] is only defined for braced structs"),
    };

    let name = &ast.ident;
    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    // XXX figure out how to avoid this
    let used_variants0 = variants.iter().filter(|field| {
            if field.attrs.iter().any(|attr| attr.name() == "ignore") { false}
            else if is_type(& field.ty, "Module") {false}
            else {true}
    });
    let used_variants1 = variants.iter().filter(|field| {
            if field.attrs.iter().any(|attr| attr.name() == "ignore") { false}
            else if is_type(& field.ty, "Module") {false}
            else {true}
    });
    let used_variants2 = variants.iter().filter(|field| {
            if field.attrs.iter().any(|attr| attr.name() == "ignore") { false}
            else if is_type(& field.ty, "Module") {false}
            else {true}
    });
    let atmatch = used_variants0
        .filter_map(|field| {
            let field_name = field.ident.as_ref().clone();
            let is_option = is_type(&field.ty, "Option");
            match get_type(&field.ty) {
                Kind::Parameter if is_option =>
                    Some( quote! {
                        if let Some(ref mut param) = self. #field_name {
                            self.delegate.add_param(stringify!(#field_name));
                        };
                    } ),
                Kind::Parameter =>
                    Some( quote! { self.delegate.add_param(stringify!(#field_name))  } ),
                Kind::ModIntf if is_option =>
                Some ( quote! {
                    if let Some(ref module) = self. #field_name {
                        self.delegate.add_module(stringify!(#field_name));
                    };
                } ),
                Kind::ModIntf =>
                    Some ( quote! { self.delegate.add_module(stringify!(#field_name) ); } ),
                _ => panic!("bad match {:?}", field.ty),
            }
        });
    let param_match = used_variants1
        .filter_map(|field| {
            let field_name = field.ident.as_ref().clone();
            let is_option = is_type(&field.ty, "Option");
            match get_type(&field.ty) {
                Kind::Parameter if is_option =>
                    Some( quote! {
                        stringify!(#field_name) => {
                        if let Some(ref mut param) = self. #field_name {
                            Some(param.v.id)
                        } else { None }},
                    } ),
                Kind::Parameter =>
                    Some( quote! { stringify!(#field_name) => Some(self. #field_name . v.id), } ),
                Kind::ModIntf =>  None,
                _ => panic!("bad match {:?}", field.ty),
            }

        });
    let module_match = used_variants2
        .filter_map(|field| {
            let field_name = field.ident.as_ref().clone();
            match get_type(&field.ty) {
                Kind::Parameter => {println!("{:?}", field.ty); None},
                Kind::ModIntf =>
                    Some( quote! { stringify!(#field_name) => &mut self. #field_name,  } ),
                _ => panic!("bad match {:?}", field.ty),
            }
        });
    let foo = quote! {
        impl #impl_generics InitModuleStruct for #name  #ty_generics  #where_clause {
            fn init_module(mut self) -> Self {
                self.delegate()._name = stringify!(#name).into();
                #(#atmatch);*
                ;
                self
            }
        }
        impl #impl_generics GetFieldStruct<T> for #name  #ty_generics  #where_clause {
            fn get_param(&mut self, name: &str) -> Option<i32> {
                match name {
                    #(#param_match)*
                    _ => panic!("unknown Parameter {}", name),
                }
            }
            fn get_module(&mut self, name: &str) -> &mut ModIntf<T> {
                match name {
                    #(#module_match)*
                    _ => {panic!("not found {}", name); },
                }
            }
        }

    };
    println!("parse is {}", foo);
    foo
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>remove debug noise<commit_after>#![crate_type = "proc-macro"]
#![recursion_limit = "192"]
#![feature(trace_macros)]
#![feature(log_syntax)]

extern crate syn;
extern crate proc_macro;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;

enum Kind {
    Module,
    Parameter,
    ModIntf,
}

#[proc_macro_derive(ModParse, attributes(ignore))]
pub fn parse(input: TokenStream) -> TokenStream {
    let source = input.to_string();
    let mut ast = syn::parse_derive_input(&source).expect("failed to parse rust syntax");
    let gen = impl_parse(&mut ast);
    gen.parse().expect("failed to serialize into rust syntax")
}
fn is_type(ty: &syn::Ty, name: &'static str) -> bool {
    if let syn::Ty::Path(_, ref path) = *ty {
        if path.segments.iter().any(|seg| seg.ident.as_ref() == name) {
            true
        } else {
            false
        }
    } else {
        false
    }
}

fn option_type(ty: &syn::Ty) -> &syn::Ty {
    if let syn::Ty::Path(_, ref path) = *ty {
        if let Some(seg) = path.segments
               .iter()
               .find(|seg| seg.ident.as_ref() == "Option") {
            if let syn::PathParameters::AngleBracketed(ref data) = seg.parameters {
                // assume simple nesting for now
                &data.types[0]
            } else {
                panic!("can't parse Option segment parameters {:?}", seg.parameters);
            }
        } else {
            panic!("Option not found!")
        }
    } else {
        panic!("not path")
    }
}

fn get_type(ty: &syn::Ty) -> Kind {
    if is_type(&ty, "Option") {
        get_type(option_type(ty))
    } else if is_type(&ty, "Module") {
        Kind::Module
    } else if is_type(&ty, "Parameter") {
        Kind::Parameter
    } else {
        Kind::ModIntf
    }
}

fn impl_parse(ast: &mut syn::DeriveInput) -> quote::Tokens {
    use syn::{Body, VariantData};

    let ref mut variants = match ast.body {
        Body::Struct(VariantData::Struct(ref vars)) => vars,
        _ => panic!("#[derive(Parse)] is only defined for braced structs"),
    };

    let name = &ast.ident;
    let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
    // XXX figure out how to avoid this
    let used_variants0 = variants.iter().filter(|field| {
            if field.attrs.iter().any(|attr| attr.name() == "ignore") { false}
            else if is_type(& field.ty, "Module") {false}
            else {true}
    });
    let used_variants1 = variants.iter().filter(|field| {
            if field.attrs.iter().any(|attr| attr.name() == "ignore") { false}
            else if is_type(& field.ty, "Module") {false}
            else {true}
    });
    let used_variants2 = variants.iter().filter(|field| {
            if field.attrs.iter().any(|attr| attr.name() == "ignore") { false}
            else if is_type(& field.ty, "Module") {false}
            else {true}
    });
    let atmatch = used_variants0
        .filter_map(|field| {
            let field_name = field.ident.as_ref().clone();
            let is_option = is_type(&field.ty, "Option");
            match get_type(&field.ty) {
                Kind::Parameter if is_option =>
                    Some( quote! {
                        if let Some(ref mut param) = self. #field_name {
                            self.delegate.add_param(stringify!(#field_name));
                        };
                    } ),
                Kind::Parameter =>
                    Some( quote! { self.delegate.add_param(stringify!(#field_name))  } ),
                Kind::ModIntf if is_option =>
                Some ( quote! {
                    if let Some(ref module) = self. #field_name {
                        self.delegate.add_module(stringify!(#field_name));
                    };
                } ),
                Kind::ModIntf =>
                    Some ( quote! { self.delegate.add_module(stringify!(#field_name) ); } ),
                _ => panic!("bad match {:?}", field.ty),
            }
        });
    let param_match = used_variants1
        .filter_map(|field| {
            let field_name = field.ident.as_ref().clone();
            let is_option = is_type(&field.ty, "Option");
            match get_type(&field.ty) {
                Kind::Parameter if is_option =>
                    Some( quote! {
                        stringify!(#field_name) => {
                        if let Some(ref mut param) = self. #field_name {
                            Some(param.v.id)
                        } else { None }},
                    } ),
                Kind::Parameter =>
                    Some( quote! { stringify!(#field_name) => Some(self. #field_name . v.id), } ),
                Kind::ModIntf =>  None,
                _ => panic!("bad match {:?}", field.ty),
            }

        });
    let module_match = used_variants2
        .filter_map(|field| {
            let field_name = field.ident.as_ref().clone();
            match get_type(&field.ty) {
                Kind::Parameter => None,
                Kind::ModIntf =>
                    Some( quote! { stringify!(#field_name) => &mut self. #field_name,  } ),
                _ => panic!("bad match {:?}", field.ty),
            }
        });
    let foo = quote! {
        impl #impl_generics InitModuleStruct for #name  #ty_generics  #where_clause {
            fn init_module(mut self) -> Self {
                self.delegate()._name = stringify!(#name).into();
                #(#atmatch);*
                ;
                self
            }
        }
        impl #impl_generics GetFieldStruct<T> for #name  #ty_generics  #where_clause {
            fn get_param(&mut self, name: &str) -> Option<i32> {
                match name {
                    #(#param_match)*
                    _ => panic!("unknown Parameter {}", name),
                }
            }
            fn get_module(&mut self, name: &str) -> &mut ModIntf<T> {
                match name {
                    #(#module_match)*
                    _ => {panic!("not found {}", name); },
                }
            }
        }

    };
    foo
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>// Copyright 2016 Mozilla
//
// 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.

#![allow(dead_code)]

/// Low-level functions for testing.

use std::borrow::Borrow;
use std::io::{Write};
use std::rc::Rc;

use itertools::Itertools;
use rusqlite;
use rusqlite::types::{ToSql};
use tabwriter::TabWriter;

use bootstrap;
use db::TypedSQLValue;
use edn;
use entids;
use errors::Result;
use mentat_core::{
    HasSchema,
    SQLValueType,
    TypedValue,
    ValueType,
};
use mentat_tx::entities::{Entid};
use schema::{
    SchemaBuilding,
};
use types::Schema;

/// Represents a *datom* (assertion) in the store.
#[derive(Clone,Debug,Eq,Hash,Ord,PartialOrd,PartialEq)]
struct Datom {
    // TODO: generalize this.
    e: Entid,
    a: Entid,
    v: edn::Value,
    tx: i64,
    added: Option<bool>,
}

/// Represents a set of datoms (assertions) in the store.
///
/// To make comparision easier, we deterministically order.  The ordering is the ascending tuple
/// ordering determined by `(e, a, (value_type_tag, v), tx)`, where `value_type_tag` is an internal
/// value that is not exposed but is deterministic.
struct Datoms(pub Vec<Datom>);

/// Represents an ordered sequence of transactions in the store.
///
/// To make comparision easier, we deterministically order.  The ordering is the ascending tuple
/// ordering determined by `(e, a, (value_type_tag, v), tx, added)`, where `value_type_tag` is an
/// internal value that is not exposed but is deterministic, and `added` is ordered such that
/// retracted assertions appear before added assertions.
struct Transactions(pub Vec<Datoms>);

/// Represents the fulltext values in the store.
pub struct FulltextValues(pub Vec<(i64, String)>);

impl Datom {
    pub fn into_edn(&self) -> edn::Value {
        let f = |entid: &Entid| -> edn::Value {
            match *entid {
                Entid::Entid(ref y) => edn::Value::Integer(y.clone()),
                Entid::Ident(ref y) => edn::Value::NamespacedKeyword(y.clone()),
            }
        };

        let mut v = vec![f(&self.e), f(&self.a), self.v.clone()];
        if let Some(added) = self.added {
            v.push(edn::Value::Integer(self.tx));
            v.push(edn::Value::Boolean(added));
        }

        edn::Value::Vector(v)
    }
}

impl Datoms {
    pub fn into_edn(&self) -> edn::Value {
        edn::Value::Vector((&self.0).into_iter().map(|x| x.into_edn()).collect())
    }
}

impl Transactions {
    pub fn into_edn(&self) -> edn::Value {
        edn::Value::Vector((&self.0).into_iter().map(|x| x.into_edn()).collect())
    }
}

impl FulltextValues {
    pub fn into_edn(&self) -> edn::Value {
        edn::Value::Vector((&self.0).into_iter().map(|&(x, ref y)| edn::Value::Vector(vec![edn::Value::Integer(x), edn::Value::Text(y.clone())])).collect())
    }
}

/// Turn TypedValue::Ref into TypedValue::Keyword when it is possible.
trait ToIdent {
  fn map_ident(self, schema: &Schema) -> Self;
}

impl ToIdent for TypedValue {
    fn map_ident(self, schema: &Schema) -> Self {
        if let TypedValue::Ref(e) = self {
            schema.get_ident(e).cloned().map(|i| TypedValue::Keyword(Rc::new(i))).unwrap_or(TypedValue::Ref(e))
        } else {
            self
        }
    }
}

/// Convert a numeric entid to an ident `Entid` if possible, otherwise a numeric `Entid`.
fn to_entid(schema: &Schema, entid: i64) -> Entid {
    schema.get_ident(entid).map_or(Entid::Entid(entid), |ident| Entid::Ident(ident.clone()))
}

/// Return the set of datoms in the store, ordered by (e, a, v, tx), but not including any datoms of
/// the form [... :db/txInstant ...].
fn datoms<S: Borrow<Schema>>(conn: &rusqlite::Connection, schema: &S) -> Result<Datoms> {
    datoms_after(conn, schema, bootstrap::TX0 - 1)
}

/// Return the set of datoms in the store with transaction ID strictly greater than the given `tx`,
/// ordered by (e, a, v, tx).
///
/// The datom set returned does not include any datoms of the form [... :db/txInstant ...].
fn datoms_after<S: Borrow<Schema>>(conn: &rusqlite::Connection, schema: &S, tx: i64) -> Result<Datoms> {
    let borrowed_schema = schema.borrow();

    let mut stmt: rusqlite::Statement = conn.prepare("SELECT e, a, v, value_type_tag, tx FROM datoms WHERE tx > ? ORDER BY e ASC, a ASC, value_type_tag ASC, v ASC, tx ASC")?;

    let r: Result<Vec<_>> = stmt.query_and_then(&[&tx], |row| {
        let e: i64 = row.get_checked(0)?;
        let a: i64 = row.get_checked(1)?;

        if a == entids::DB_TX_INSTANT {
            return Ok(None);
        }

        let v: rusqlite::types::Value = row.get_checked(2)?;
        let value_type_tag: i32 = row.get_checked(3)?;

        let attribute = borrowed_schema.require_attribute_for_entid(a)?;
        let value_type_tag = if !attribute.fulltext { value_type_tag } else { ValueType::Long.value_type_tag() };

        let typed_value = TypedValue::from_sql_value_pair(v, value_type_tag)?.map_ident(borrowed_schema);
        let (value, _) = typed_value.to_edn_value_pair();

        let tx: i64 = row.get_checked(4)?;

        Ok(Some(Datom {
            e: Entid::Entid(e),
            a: to_entid(borrowed_schema, a),
            v: value,
            tx: tx,
            added: None,
        }))
    })?.collect();

    Ok(Datoms(r?.into_iter().filter_map(|x| x).collect()))
}

/// Return the sequence of transactions in the store with transaction ID strictly greater than the
/// given `tx`, ordered by (tx, e, a, v).
///
/// Each transaction returned includes the [:db/tx :db/txInstant ...] datom.
fn transactions_after<S: Borrow<Schema>>(conn: &rusqlite::Connection, schema: &S, tx: i64) -> Result<Transactions> {
    let borrowed_schema = schema.borrow();

    let mut stmt: rusqlite::Statement = conn.prepare("SELECT e, a, v, value_type_tag, tx, added FROM transactions WHERE tx > ? ORDER BY tx ASC, e ASC, a ASC, value_type_tag ASC, v ASC, added ASC")?;

    let r: Result<Vec<_>> = stmt.query_and_then(&[&tx], |row| {
        let e: i64 = row.get_checked(0)?;
        let a: i64 = row.get_checked(1)?;

        let v: rusqlite::types::Value = row.get_checked(2)?;
        let value_type_tag: i32 = row.get_checked(3)?;

        let attribute = borrowed_schema.require_attribute_for_entid(a)?;
        let value_type_tag = if !attribute.fulltext { value_type_tag } else { ValueType::Long.value_type_tag() };

        let typed_value = TypedValue::from_sql_value_pair(v, value_type_tag)?.map_ident(borrowed_schema);
        let (value, _) = typed_value.to_edn_value_pair();

        let tx: i64 = row.get_checked(4)?;
        let added: bool = row.get_checked(5)?;

        Ok(Datom {
            e: Entid::Entid(e),
            a: to_entid(borrowed_schema, a),
            v: value,
            tx: tx,
            added: Some(added),
        })
    })?.collect();

    // Group by tx.
    let r: Vec<Datoms> = r?.into_iter().group_by(|x| x.tx).into_iter().map(|(_key, group)| Datoms(group.collect())).collect();
    Ok(Transactions(r))
}

/// Return the set of fulltext values in the store, ordered by rowid.
pub fn fulltext_values(conn: &rusqlite::Connection) -> Result<FulltextValues> {
    let mut stmt: rusqlite::Statement = conn.prepare("SELECT rowid, text FROM fulltext_values ORDER BY rowid")?;

    let r: Result<Vec<_>> = stmt.query_and_then(&[], |row| {
        let rowid: i64 = row.get_checked(0)?;
        let text: String = row.get_checked(1)?;
        Ok((rowid, text))
    })?.collect();

    r.map(FulltextValues)
}

/// Execute the given `sql` query with the given `params` and format the results as a
/// tab-and-newline formatted string suitable for debug printing.
///
/// The query is printed followed by a newline, then the returned columns followed by a newline, and
/// then the data rows and columns.  All columns are aligned.
pub fn dump_sql_query(conn: &rusqlite::Connection, sql: &str, params: &[&ToSql]) -> Result<String> {
    let mut stmt: rusqlite::Statement = conn.prepare(sql)?;

    let mut tw = TabWriter::new(Vec::new()).padding(2);
    write!(&mut tw, "{}\n", sql).unwrap();

    for column_name in stmt.column_names() {
        write!(&mut tw, "{}\t", column_name).unwrap();
    }
    write!(&mut tw, "\n").unwrap();

    let r: Result<Vec<_>> = stmt.query_and_then(params, |row| {
        for i in 0..row.column_count() {
            let value: rusqlite::types::Value = row.get_checked(i)?;
            write!(&mut tw, "{:?}\t", value).unwrap();
        }
        write!(&mut tw, "\n").unwrap();
        Ok(())
    })?.collect();
    r?;

    let dump = String::from_utf8(tw.into_inner().unwrap()).unwrap();
    Ok(dump)
}
<commit_msg>Revert "Make debug structs and functions non-public. r=grisha"<commit_after>// Copyright 2016 Mozilla
//
// 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.

#![allow(dead_code)]

/// Low-level functions for testing.

use std::borrow::Borrow;
use std::io::{Write};
use std::rc::Rc;

use itertools::Itertools;
use rusqlite;
use rusqlite::types::{ToSql};
use tabwriter::TabWriter;

use bootstrap;
use db::TypedSQLValue;
use edn;
use entids;
use errors::Result;
use mentat_core::{
    HasSchema,
    SQLValueType,
    TypedValue,
    ValueType,
};
use mentat_tx::entities::{Entid};
use schema::{
    SchemaBuilding,
};
use types::Schema;

/// Represents a *datom* (assertion) in the store.
#[derive(Clone,Debug,Eq,Hash,Ord,PartialOrd,PartialEq)]
pub struct Datom {
    // TODO: generalize this.
    e: Entid,
    a: Entid,
    v: edn::Value,
    tx: i64,
    added: Option<bool>,
}

/// Represents a set of datoms (assertions) in the store.
///
/// To make comparision easier, we deterministically order.  The ordering is the ascending tuple
/// ordering determined by `(e, a, (value_type_tag, v), tx)`, where `value_type_tag` is an internal
/// value that is not exposed but is deterministic.
pub struct Datoms(pub Vec<Datom>);

/// Represents an ordered sequence of transactions in the store.
///
/// To make comparision easier, we deterministically order.  The ordering is the ascending tuple
/// ordering determined by `(e, a, (value_type_tag, v), tx, added)`, where `value_type_tag` is an
/// internal value that is not exposed but is deterministic, and `added` is ordered such that
/// retracted assertions appear before added assertions.
pub struct Transactions(pub Vec<Datoms>);

/// Represents the fulltext values in the store.
pub struct FulltextValues(pub Vec<(i64, String)>);

impl Datom {
    pub fn into_edn(&self) -> edn::Value {
        let f = |entid: &Entid| -> edn::Value {
            match *entid {
                Entid::Entid(ref y) => edn::Value::Integer(y.clone()),
                Entid::Ident(ref y) => edn::Value::NamespacedKeyword(y.clone()),
            }
        };

        let mut v = vec![f(&self.e), f(&self.a), self.v.clone()];
        if let Some(added) = self.added {
            v.push(edn::Value::Integer(self.tx));
            v.push(edn::Value::Boolean(added));
        }

        edn::Value::Vector(v)
    }
}

impl Datoms {
    pub fn into_edn(&self) -> edn::Value {
        edn::Value::Vector((&self.0).into_iter().map(|x| x.into_edn()).collect())
    }
}

impl Transactions {
    pub fn into_edn(&self) -> edn::Value {
        edn::Value::Vector((&self.0).into_iter().map(|x| x.into_edn()).collect())
    }
}

impl FulltextValues {
    pub fn into_edn(&self) -> edn::Value {
        edn::Value::Vector((&self.0).into_iter().map(|&(x, ref y)| edn::Value::Vector(vec![edn::Value::Integer(x), edn::Value::Text(y.clone())])).collect())
    }
}

/// Turn TypedValue::Ref into TypedValue::Keyword when it is possible.
trait ToIdent {
  fn map_ident(self, schema: &Schema) -> Self;
}

impl ToIdent for TypedValue {
    fn map_ident(self, schema: &Schema) -> Self {
        if let TypedValue::Ref(e) = self {
            schema.get_ident(e).cloned().map(|i| TypedValue::Keyword(Rc::new(i))).unwrap_or(TypedValue::Ref(e))
        } else {
            self
        }
    }
}

/// Convert a numeric entid to an ident `Entid` if possible, otherwise a numeric `Entid`.
fn to_entid(schema: &Schema, entid: i64) -> Entid {
    schema.get_ident(entid).map_or(Entid::Entid(entid), |ident| Entid::Ident(ident.clone()))
}

/// Return the set of datoms in the store, ordered by (e, a, v, tx), but not including any datoms of
/// the form [... :db/txInstant ...].
pub fn datoms<S: Borrow<Schema>>(conn: &rusqlite::Connection, schema: &S) -> Result<Datoms> {
    datoms_after(conn, schema, bootstrap::TX0 - 1)
}

/// Return the set of datoms in the store with transaction ID strictly greater than the given `tx`,
/// ordered by (e, a, v, tx).
///
/// The datom set returned does not include any datoms of the form [... :db/txInstant ...].
pub fn datoms_after<S: Borrow<Schema>>(conn: &rusqlite::Connection, schema: &S, tx: i64) -> Result<Datoms> {
    let borrowed_schema = schema.borrow();

    let mut stmt: rusqlite::Statement = conn.prepare("SELECT e, a, v, value_type_tag, tx FROM datoms WHERE tx > ? ORDER BY e ASC, a ASC, value_type_tag ASC, v ASC, tx ASC")?;

    let r: Result<Vec<_>> = stmt.query_and_then(&[&tx], |row| {
        let e: i64 = row.get_checked(0)?;
        let a: i64 = row.get_checked(1)?;

        if a == entids::DB_TX_INSTANT {
            return Ok(None);
        }

        let v: rusqlite::types::Value = row.get_checked(2)?;
        let value_type_tag: i32 = row.get_checked(3)?;

        let attribute = borrowed_schema.require_attribute_for_entid(a)?;
        let value_type_tag = if !attribute.fulltext { value_type_tag } else { ValueType::Long.value_type_tag() };

        let typed_value = TypedValue::from_sql_value_pair(v, value_type_tag)?.map_ident(borrowed_schema);
        let (value, _) = typed_value.to_edn_value_pair();

        let tx: i64 = row.get_checked(4)?;

        Ok(Some(Datom {
            e: Entid::Entid(e),
            a: to_entid(borrowed_schema, a),
            v: value,
            tx: tx,
            added: None,
        }))
    })?.collect();

    Ok(Datoms(r?.into_iter().filter_map(|x| x).collect()))
}

/// Return the sequence of transactions in the store with transaction ID strictly greater than the
/// given `tx`, ordered by (tx, e, a, v).
///
/// Each transaction returned includes the [:db/tx :db/txInstant ...] datom.
pub fn transactions_after<S: Borrow<Schema>>(conn: &rusqlite::Connection, schema: &S, tx: i64) -> Result<Transactions> {
    let borrowed_schema = schema.borrow();

    let mut stmt: rusqlite::Statement = conn.prepare("SELECT e, a, v, value_type_tag, tx, added FROM transactions WHERE tx > ? ORDER BY tx ASC, e ASC, a ASC, value_type_tag ASC, v ASC, added ASC")?;

    let r: Result<Vec<_>> = stmt.query_and_then(&[&tx], |row| {
        let e: i64 = row.get_checked(0)?;
        let a: i64 = row.get_checked(1)?;

        let v: rusqlite::types::Value = row.get_checked(2)?;
        let value_type_tag: i32 = row.get_checked(3)?;

        let attribute = borrowed_schema.require_attribute_for_entid(a)?;
        let value_type_tag = if !attribute.fulltext { value_type_tag } else { ValueType::Long.value_type_tag() };

        let typed_value = TypedValue::from_sql_value_pair(v, value_type_tag)?.map_ident(borrowed_schema);
        let (value, _) = typed_value.to_edn_value_pair();

        let tx: i64 = row.get_checked(4)?;
        let added: bool = row.get_checked(5)?;

        Ok(Datom {
            e: Entid::Entid(e),
            a: to_entid(borrowed_schema, a),
            v: value,
            tx: tx,
            added: Some(added),
        })
    })?.collect();

    // Group by tx.
    let r: Vec<Datoms> = r?.into_iter().group_by(|x| x.tx).into_iter().map(|(_key, group)| Datoms(group.collect())).collect();
    Ok(Transactions(r))
}

/// Return the set of fulltext values in the store, ordered by rowid.
pub fn fulltext_values(conn: &rusqlite::Connection) -> Result<FulltextValues> {
    let mut stmt: rusqlite::Statement = conn.prepare("SELECT rowid, text FROM fulltext_values ORDER BY rowid")?;

    let r: Result<Vec<_>> = stmt.query_and_then(&[], |row| {
        let rowid: i64 = row.get_checked(0)?;
        let text: String = row.get_checked(1)?;
        Ok((rowid, text))
    })?.collect();

    r.map(FulltextValues)
}

/// Execute the given `sql` query with the given `params` and format the results as a
/// tab-and-newline formatted string suitable for debug printing.
///
/// The query is printed followed by a newline, then the returned columns followed by a newline, and
/// then the data rows and columns.  All columns are aligned.
pub fn dump_sql_query(conn: &rusqlite::Connection, sql: &str, params: &[&ToSql]) -> Result<String> {
    let mut stmt: rusqlite::Statement = conn.prepare(sql)?;

    let mut tw = TabWriter::new(Vec::new()).padding(2);
    write!(&mut tw, "{}\n", sql).unwrap();

    for column_name in stmt.column_names() {
        write!(&mut tw, "{}\t", column_name).unwrap();
    }
    write!(&mut tw, "\n").unwrap();

    let r: Result<Vec<_>> = stmt.query_and_then(params, |row| {
        for i in 0..row.column_count() {
            let value: rusqlite::types::Value = row.get_checked(i)?;
            write!(&mut tw, "{:?}\t", value).unwrap();
        }
        write!(&mut tw, "\n").unwrap();
        Ok(())
    })?.collect();
    r?;

    let dump = String::from_utf8(tw.into_inner().unwrap()).unwrap();
    Ok(dump)
}
<|endoftext|>