<commit_before>#![deny(warnings)]
pub mod persistable;
pub mod types;

mod connection;
mod db_result;
mod query_source;
mod result;
mod row;

#[macro_use]
mod macros;

pub use result::*;
pub use query_source::{QuerySource, Queriable, Table, Column, JoinTo};
pub use connection::Connection;

#[cfg(test)]
mod test_usage_without_compiler_plugins {
    pub use super::*;
    use types::NativeSqlType;

    #[derive(PartialEq, Eq, Debug)]
    struct User {
        id: i32,
        name: String,
        hair_color: Option<String>,
    }

    impl User {
        fn new(id: i32, name: &str) -> Self {
            User { id: id, name: name.to_string(), hair_color: None }
        }
    }

    #[derive(PartialEq, Eq, Debug)]
    struct UserWithoutId {
        name: String,
        hair_color: Option<String>,
    }

    #[derive(PartialEq, Eq, Debug)]
    struct Post {
        id: i32,
        user_id: i32,
        title: String,
    }

    // Compiler plugin will automatically invoke this based on schema
    table! {
        users {
            id -> Serial,
            name -> VarChar,
            hair_color -> Nullable<VarChar>,
        }
    }

    table! {
        posts {
            id -> Serial,
            user_id -> Integer,
            title -> VarChar,
        }
    }

    // Compiler plugin will replace this with #[derive(Queriable)]
    queriable! {
        User {
            id -> i32,
            name -> String,
            hair_color -> Option<String>,
        }
    }

    queriable! {
        UserWithoutId {
            name -> String,
            hair_color -> Option<String>,
        }
    }

    queriable! {
        Post {
            id -> i32,
            user_id -> i32,
            title -> String,
        }
    }

    joinable!(posts -> users (user_id = id));
    belongs_to!(User, users, Post, posts);

    #[test]
    fn selecting_basic_data() {
        let connection = connection();
        setup_users_table(&connection);
        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();

        let expected_data = vec![
            (1, "Sean".to_string(), None::<String>),
            (2, "Tess".to_string(), None::<String>),
         ];
        let actual_data: Vec<_> = connection.query_all(&users::table)
            .unwrap().collect();
        assert_eq!(expected_data, actual_data);
    }

    #[test]
    fn selecting_a_struct() {
        let connection = connection();
        setup_users_table(&connection);
        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();

        let expected_users = vec![
            User::new(1, "Sean"),
            User::new(2, "Tess"),
        ];
        let actual_users: Vec<_> = connection.query_all(&users::table)
            .unwrap().collect();
        assert_eq!(expected_users, actual_users);
    }

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

        let connection = connection();
        setup_users_table(&connection);
        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();

        let select_id = users.select(id);
        // This should fail type checking, and we should add a test to ensure
        // it continues to fail to compile.
        // let select_id = users.select(posts::id);
        let select_name = users.select(name);
        let ids: Vec<_> = connection.query_all(&select_id)
            .unwrap().collect();
        let names: Vec<String> = connection.query_all(&select_name)
            .unwrap().collect();
        // This should fail type checking, and we should add a test to ensure
        // it continues to fail to compile.
        // let names: Vec<String> = connection.query_all(&select_id)
        //     .unwrap().collect();

        assert_eq!(vec![1, 2], ids);
        assert_eq!(vec!["Sean".to_string(), "Tess".to_string()], names);
    }

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

        let connection = connection();
        setup_users_table(&connection);
        connection.execute("INSERT INTO users (name, hair_color) VALUES ('Jim', 'Black'), ('Bob', 'Brown')")
            .unwrap();

        let source = users.select((name, hair_color));
        // This should fail type checking, and we should add a test to ensure
        // it continues to fail to compile.
        // let source = users.select((posts::title, posts::user_id));
        // let source = users.select((posts::title, name));
        let expected_data = vec![
            ("Jim".to_string(), Some("Black".to_string())),
            ("Bob".to_string(), Some("Brown".to_string())),
        ];
        let actual_data: Vec<_> = connection.query_all(&source)
            .unwrap().collect();

        assert_eq!(expected_data, actual_data);
    }

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

        let connection = connection();
        setup_users_table(&connection);
        connection.execute("INSERT INTO users (name, hair_color) VALUES ('Jim', 'Black'), ('Bob', 'Brown')")
            .unwrap();

        let source = users.select((name, hair_color));
        let expected_data = vec![
            UserWithoutId { name: "Jim".to_string(), hair_color: Some("Black".to_string()) },
            UserWithoutId { name: "Bob".to_string(), hair_color: Some("Brown".to_string()) },
        ];
        let actual_data: Vec<_> = connection.query_all(&source)
            .unwrap().collect();

        assert_eq!(expected_data, actual_data);
    }

    #[test]
    fn with_select_sql() {
        let connection = connection();
        setup_users_table(&connection);
        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();

        let select_count = users::table.select_sql::<types::BigInt>("COUNT(*)");
        let get_count = || connection.query_one::<_, i64>(&select_count).unwrap();
        // This should fail type checking, and we should add a test to ensure
        // it continues to fail to compile.
        // let actual_count = connection.query_one::<_, String>(&select_count).unwrap();

        assert_eq!(Some(2), get_count());

        connection.execute("INSERT INTO users (name) VALUES ('Jim')")
            .unwrap();

        assert_eq!(Some(3), get_count());
    }

    #[test]
    fn belongs_to() {
        let connection = connection();
        setup_users_table(&connection);
        setup_posts_table(&connection);

        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();
        connection.execute("INSERT INTO posts (user_id, title) VALUES
            (1, 'Hello'),
            (2, 'World')
        ").unwrap();

        let sean = User::new(1, "Sean");
        let tess = User::new(2, "Tess");
        let seans_post = Post { id: 1, user_id: 1, title: "Hello".to_string() };
        let tess_post = Post { id: 2, user_id: 2, title: "World".to_string() };

        let expected_data = vec![(seans_post, sean), (tess_post, tess)];
        let source = posts::table.inner_join(users::table);
        let actual_data: Vec<_> = connection.query_all(&source).unwrap().collect();

        assert_eq!(expected_data, actual_data);
    }

    #[test]
    fn select_single_from_join() {
        let connection = connection();
        setup_users_table(&connection);
        setup_posts_table(&connection);

        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();
        connection.execute("INSERT INTO posts (user_id, title) VALUES
            (1, 'Hello'),
            (2, 'World')
        ").unwrap();

        let source = posts::table.inner_join(users::table);
        let select_name = source.select(users::name);
        let select_title = source.select(posts::title);

        let expected_names = vec!["Sean".to_string(), "Tess".to_string()];
        let actual_names: Vec<String> = connection.query_all(&select_name).unwrap().collect();

        assert_eq!(expected_names, actual_names);

        let expected_titles = vec!["Hello".to_string(), "World".to_string()];
        let actual_titles: Vec<String> = connection.query_all(&select_title).unwrap().collect();

        assert_eq!(expected_titles, actual_titles);
    }

    #[test]
    fn select_multiple_from_join() {
        let connection = connection();
        setup_users_table(&connection);
        setup_posts_table(&connection);

        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();
        connection.execute("INSERT INTO posts (user_id, title) VALUES
            (1, 'Hello'),
            (2, 'World')
        ").unwrap();

        let source = posts::table.inner_join(users::table)
            .select((users::name, posts::title));

        let expected_data = vec![
            ("Sean".to_string(), "Hello".to_string()),
            ("Tess".to_string(), "World".to_string()),
        ];
        let actual_data: Vec<_> = connection.query_all(&source).unwrap().collect();

        assert_eq!(expected_data, actual_data);
    }

    #[test]
    fn select_only_one_side_of_join() {
        let connection = connection();
        setup_users_table(&connection);
        setup_posts_table(&connection);

        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();
        connection.execute("INSERT INTO posts (user_id, title) VALUES (2, 'Hello')")
            .unwrap();

        let source = users::table.inner_join(posts::table).select(users::star);

        let expected_data = vec![User::new(2, "Tess")];
        let actual_data: Vec<_> = connection.query_all(&source).unwrap().collect();

        assert_eq!(expected_data, actual_data);
    }

    #[test]
    fn find() {
        use self::users::table as users;

        let connection = connection();
        setup_users_table(&connection);

        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();

        assert_eq!(Ok(Some(User::new(1, "Sean"))), connection.find(&users, &1));
        assert_eq!(Ok(Some(User::new(2, "Tess"))), connection.find(&users, &2));
        assert_eq!(Ok(None::<User>), connection.find(&users, &3));
        // This should fail type checking, and we should add a test to ensure
        // it continues to fail to compile.
        // connection.find(&users, &"1").unwrap();
    }

    table! {
        users_with_name_pk (name) {
            name -> VarChar,
        }
    }

    #[test]
    fn find_with_non_serial_pk() {
        use self::users_with_name_pk::table as users;

        let connection = connection();
        connection.execute("CREATE TABLE users_with_name_pk (name VARCHAR PRIMARY KEY)")
            .unwrap();
        connection.execute("INSERT INTO users_with_name_pk (name) VALUES ('Sean'), ('Tess')")
            .unwrap();

        assert_eq!(Ok(Some("Sean".to_string())), connection.find(&users, &"Sean"));
        assert_eq!(Ok(Some("Tess".to_string())), connection.find(&users, &"Tess".to_string()));
        assert_eq!(Ok(None::<String>), connection.find(&users, &"Wibble"));
        // This should fail type checking, and we should add a test to ensure
        // it continues to fail to compile.
        // connection.find(&users, &1).unwrap();
    }

    fn connection() -> Connection {
        let connection_url = ::std::env::var("DATABASE_URL").ok()
            .expect("DATABASE_URL must be set in order to run tests");
        let result = Connection::establish(&connection_url).unwrap();
        result.execute("BEGIN").unwrap();
        result
    }

    #[test]
    fn insert_records() {
        use self::users::table as users;
        let connection = connection();
        setup_users_table(&connection);

        let new_users = vec![
            NewUser::new("Sean", Some("Black")),
            NewUser::new("Tess", None),
        ];
        let inserted_users: Vec<_> = connection.insert(&users, new_users).unwrap().collect();

        let expected_users = vec![
            User { id: 1, name: "Sean".to_string(), hair_color: Some("Black".to_string()) },
            User { id: 2, name: "Tess".to_string(), hair_color: None },
        ];
        let actual_users: Vec<_> = connection.query_all(&users).unwrap().collect();

        assert_eq!(expected_users, actual_users);
        assert_eq!(expected_users, inserted_users);
    }

    #[test]
    fn insert_with_defaults() {
        use self::users::table as users;
        let connection = connection();
        connection.execute("CREATE TABLE users (
            id SERIAL PRIMARY KEY,
            name VARCHAR NOT NULL,
            hair_color VARCHAR NOT NULL DEFAULT 'Green'
        )").unwrap();
        let new_users = vec![
            NewUser::new("Sean", Some("Black")),
            NewUser::new("Tess", None),
        ];
        let inserted_users: Vec<_> = connection.insert(&users, new_users).unwrap().collect();

        let expected_users = vec![
            User { id: 1, name: "Sean".to_string(), hair_color: Some("Black".to_string()) },
            User { id: 2, name: "Tess".to_string(), hair_color: Some("Green".to_string()) },
        ];
        let actual_users: Vec<_> = connection.query_all(&users).unwrap().collect();

        assert_eq!(expected_users, actual_users);
        assert_eq!(expected_users, inserted_users);
    }

    #[test]
    fn insert_with_defaults_not_provided() {
        use self::users::table as users;
        let connection = connection();
        connection.execute("CREATE TABLE users (
            id SERIAL PRIMARY KEY,
            name VARCHAR NOT NULL,
            hair_color VARCHAR NOT NULL DEFAULT 'Green'
        )").unwrap();
        let new_users = vec![
            BaldUser { name: "Sean".to_string() },
            BaldUser { name: "Tess".to_string() },
        ];
        let inserted_users: Vec<_> = connection.insert(&users, new_users).unwrap().collect();

        let expected_users = vec![
            User { id: 1, name: "Sean".to_string(), hair_color: Some("Green".to_string()) },
            User { id: 2, name: "Tess".to_string(), hair_color: Some("Green".to_string()) },
        ];
        let actual_users: Vec<_> = connection.query_all(&users).unwrap().collect();

        assert_eq!(expected_users, actual_users);
        assert_eq!(expected_users, inserted_users);
    }

    struct NewUser {
        name: String,
        hair_color: Option<String>,
    }

    struct BaldUser {
        name: String,
    }

    impl NewUser {
        fn new(name: &str, hair_color: Option<&str>) -> Self {
            NewUser {
                name: name.to_string(),
                hair_color: hair_color.map(|s| s.to_string()),
            }
        }
    }

    insertable! {
        NewUser -> users {
            name -> String,
            hair_color -> Option<String>,
        }
    }

    insertable! {
        BaldUser -> users {
            name -> String,
        }
    }

    fn setup_users_table(connection: &Connection) {
        connection.execute("CREATE TABLE users (
            id SERIAL PRIMARY KEY,
            name VARCHAR NOT NULL,
            hair_color VARCHAR
        )").unwrap();
    }

    fn setup_posts_table(connection: &Connection) {
        connection.execute("CREATE TABLE posts (
            id SERIAL PRIMARY KEY,
            user_id INTEGER NOT NULL,
            title VARCHAR NOT NULL
        )").unwrap();
    }
}
<commit_msg>Remove redundant struct from tests<commit_after>#![deny(warnings)]
pub mod persistable;
pub mod types;

mod connection;
mod db_result;
mod query_source;
mod result;
mod row;

#[macro_use]
mod macros;

pub use result::*;
pub use query_source::{QuerySource, Queriable, Table, Column, JoinTo};
pub use connection::Connection;

#[cfg(test)]
mod test_usage_without_compiler_plugins {
    pub use super::*;
    use types::NativeSqlType;

    #[derive(PartialEq, Eq, Debug)]
    struct User {
        id: i32,
        name: String,
        hair_color: Option<String>,
    }

    impl User {
        fn new(id: i32, name: &str) -> Self {
            User { id: id, name: name.to_string(), hair_color: None }
        }
    }

    #[derive(PartialEq, Eq, Debug)]
    struct Post {
        id: i32,
        user_id: i32,
        title: String,
    }

    // Compiler plugin will automatically invoke this based on schema
    table! {
        users {
            id -> Serial,
            name -> VarChar,
            hair_color -> Nullable<VarChar>,
        }
    }

    table! {
        posts {
            id -> Serial,
            user_id -> Integer,
            title -> VarChar,
        }
    }

    // Compiler plugin will replace this with #[derive(Queriable)]
    queriable! {
        User {
            id -> i32,
            name -> String,
            hair_color -> Option<String>,
        }
    }

    queriable! {
        Post {
            id -> i32,
            user_id -> i32,
            title -> String,
        }
    }

    joinable!(posts -> users (user_id = id));
    belongs_to!(User, users, Post, posts);

    #[test]
    fn selecting_basic_data() {
        let connection = connection();
        setup_users_table(&connection);
        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();

        let expected_data = vec![
            (1, "Sean".to_string(), None::<String>),
            (2, "Tess".to_string(), None::<String>),
         ];
        let actual_data: Vec<_> = connection.query_all(&users::table)
            .unwrap().collect();
        assert_eq!(expected_data, actual_data);
    }

    #[test]
    fn selecting_a_struct() {
        let connection = connection();
        setup_users_table(&connection);
        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();

        let expected_users = vec![
            User::new(1, "Sean"),
            User::new(2, "Tess"),
        ];
        let actual_users: Vec<_> = connection.query_all(&users::table)
            .unwrap().collect();
        assert_eq!(expected_users, actual_users);
    }

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

        let connection = connection();
        setup_users_table(&connection);
        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();

        let select_id = users.select(id);
        // This should fail type checking, and we should add a test to ensure
        // it continues to fail to compile.
        // let select_id = users.select(posts::id);
        let select_name = users.select(name);
        let ids: Vec<_> = connection.query_all(&select_id)
            .unwrap().collect();
        let names: Vec<String> = connection.query_all(&select_name)
            .unwrap().collect();
        // This should fail type checking, and we should add a test to ensure
        // it continues to fail to compile.
        // let names: Vec<String> = connection.query_all(&select_id)
        //     .unwrap().collect();

        assert_eq!(vec![1, 2], ids);
        assert_eq!(vec!["Sean".to_string(), "Tess".to_string()], names);
    }

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

        let connection = connection();
        setup_users_table(&connection);
        connection.execute("INSERT INTO users (name, hair_color) VALUES ('Jim', 'Black'), ('Bob', 'Brown')")
            .unwrap();

        let source = users.select((name, hair_color));
        // This should fail type checking, and we should add a test to ensure
        // it continues to fail to compile.
        // let source = users.select((posts::title, posts::user_id));
        // let source = users.select((posts::title, name));
        let expected_data = vec![
            ("Jim".to_string(), Some("Black".to_string())),
            ("Bob".to_string(), Some("Brown".to_string())),
        ];
        let actual_data: Vec<_> = connection.query_all(&source)
            .unwrap().collect();

        assert_eq!(expected_data, actual_data);
    }

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

        let connection = connection();
        setup_users_table(&connection);
        connection.execute("INSERT INTO users (name, hair_color) VALUES ('Jim', 'Black'), ('Bob', 'Brown')")
            .unwrap();

        let source = users.select((name, hair_color));
        let expected_data = vec![
            NewUser::new("Jim", Some("Black")),
            NewUser::new("Bob", Some("Brown")),
        ];
        let actual_data: Vec<_> = connection.query_all(&source)
            .unwrap().collect();

        assert_eq!(expected_data, actual_data);
    }

    #[test]
    fn with_select_sql() {
        let connection = connection();
        setup_users_table(&connection);
        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();

        let select_count = users::table.select_sql::<types::BigInt>("COUNT(*)");
        let get_count = || connection.query_one::<_, i64>(&select_count).unwrap();
        // This should fail type checking, and we should add a test to ensure
        // it continues to fail to compile.
        // let actual_count = connection.query_one::<_, String>(&select_count).unwrap();

        assert_eq!(Some(2), get_count());

        connection.execute("INSERT INTO users (name) VALUES ('Jim')")
            .unwrap();

        assert_eq!(Some(3), get_count());
    }

    #[test]
    fn belongs_to() {
        let connection = connection();
        setup_users_table(&connection);
        setup_posts_table(&connection);

        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();
        connection.execute("INSERT INTO posts (user_id, title) VALUES
            (1, 'Hello'),
            (2, 'World')
        ").unwrap();

        let sean = User::new(1, "Sean");
        let tess = User::new(2, "Tess");
        let seans_post = Post { id: 1, user_id: 1, title: "Hello".to_string() };
        let tess_post = Post { id: 2, user_id: 2, title: "World".to_string() };

        let expected_data = vec![(seans_post, sean), (tess_post, tess)];
        let source = posts::table.inner_join(users::table);
        let actual_data: Vec<_> = connection.query_all(&source).unwrap().collect();

        assert_eq!(expected_data, actual_data);
    }

    #[test]
    fn select_single_from_join() {
        let connection = connection();
        setup_users_table(&connection);
        setup_posts_table(&connection);

        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();
        connection.execute("INSERT INTO posts (user_id, title) VALUES
            (1, 'Hello'),
            (2, 'World')
        ").unwrap();

        let source = posts::table.inner_join(users::table);
        let select_name = source.select(users::name);
        let select_title = source.select(posts::title);

        let expected_names = vec!["Sean".to_string(), "Tess".to_string()];
        let actual_names: Vec<String> = connection.query_all(&select_name).unwrap().collect();

        assert_eq!(expected_names, actual_names);

        let expected_titles = vec!["Hello".to_string(), "World".to_string()];
        let actual_titles: Vec<String> = connection.query_all(&select_title).unwrap().collect();

        assert_eq!(expected_titles, actual_titles);
    }

    #[test]
    fn select_multiple_from_join() {
        let connection = connection();
        setup_users_table(&connection);
        setup_posts_table(&connection);

        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();
        connection.execute("INSERT INTO posts (user_id, title) VALUES
            (1, 'Hello'),
            (2, 'World')
        ").unwrap();

        let source = posts::table.inner_join(users::table)
            .select((users::name, posts::title));

        let expected_data = vec![
            ("Sean".to_string(), "Hello".to_string()),
            ("Tess".to_string(), "World".to_string()),
        ];
        let actual_data: Vec<_> = connection.query_all(&source).unwrap().collect();

        assert_eq!(expected_data, actual_data);
    }

    #[test]
    fn select_only_one_side_of_join() {
        let connection = connection();
        setup_users_table(&connection);
        setup_posts_table(&connection);

        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();
        connection.execute("INSERT INTO posts (user_id, title) VALUES (2, 'Hello')")
            .unwrap();

        let source = users::table.inner_join(posts::table).select(users::star);

        let expected_data = vec![User::new(2, "Tess")];
        let actual_data: Vec<_> = connection.query_all(&source).unwrap().collect();

        assert_eq!(expected_data, actual_data);
    }

    #[test]
    fn find() {
        use self::users::table as users;

        let connection = connection();
        setup_users_table(&connection);

        connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Tess')")
            .unwrap();

        assert_eq!(Ok(Some(User::new(1, "Sean"))), connection.find(&users, &1));
        assert_eq!(Ok(Some(User::new(2, "Tess"))), connection.find(&users, &2));
        assert_eq!(Ok(None::<User>), connection.find(&users, &3));
        // This should fail type checking, and we should add a test to ensure
        // it continues to fail to compile.
        // connection.find(&users, &"1").unwrap();
    }

    table! {
        users_with_name_pk (name) {
            name -> VarChar,
        }
    }

    #[test]
    fn find_with_non_serial_pk() {
        use self::users_with_name_pk::table as users;

        let connection = connection();
        connection.execute("CREATE TABLE users_with_name_pk (name VARCHAR PRIMARY KEY)")
            .unwrap();
        connection.execute("INSERT INTO users_with_name_pk (name) VALUES ('Sean'), ('Tess')")
            .unwrap();

        assert_eq!(Ok(Some("Sean".to_string())), connection.find(&users, &"Sean"));
        assert_eq!(Ok(Some("Tess".to_string())), connection.find(&users, &"Tess".to_string()));
        assert_eq!(Ok(None::<String>), connection.find(&users, &"Wibble"));
        // This should fail type checking, and we should add a test to ensure
        // it continues to fail to compile.
        // connection.find(&users, &1).unwrap();
    }

    fn connection() -> Connection {
        let connection_url = ::std::env::var("DATABASE_URL").ok()
            .expect("DATABASE_URL must be set in order to run tests");
        let result = Connection::establish(&connection_url).unwrap();
        result.execute("BEGIN").unwrap();
        result
    }

    #[test]
    fn insert_records() {
        use self::users::table as users;
        let connection = connection();
        setup_users_table(&connection);

        let new_users = vec![
            NewUser::new("Sean", Some("Black")),
            NewUser::new("Tess", None),
        ];
        let inserted_users: Vec<_> = connection.insert(&users, new_users).unwrap().collect();

        let expected_users = vec![
            User { id: 1, name: "Sean".to_string(), hair_color: Some("Black".to_string()) },
            User { id: 2, name: "Tess".to_string(), hair_color: None },
        ];
        let actual_users: Vec<_> = connection.query_all(&users).unwrap().collect();

        assert_eq!(expected_users, actual_users);
        assert_eq!(expected_users, inserted_users);
    }

    #[test]
    fn insert_with_defaults() {
        use self::users::table as users;
        let connection = connection();
        connection.execute("CREATE TABLE users (
            id SERIAL PRIMARY KEY,
            name VARCHAR NOT NULL,
            hair_color VARCHAR NOT NULL DEFAULT 'Green'
        )").unwrap();
        let new_users = vec![
            NewUser::new("Sean", Some("Black")),
            NewUser::new("Tess", None),
        ];
        let inserted_users: Vec<_> = connection.insert(&users, new_users).unwrap().collect();

        let expected_users = vec![
            User { id: 1, name: "Sean".to_string(), hair_color: Some("Black".to_string()) },
            User { id: 2, name: "Tess".to_string(), hair_color: Some("Green".to_string()) },
        ];
        let actual_users: Vec<_> = connection.query_all(&users).unwrap().collect();

        assert_eq!(expected_users, actual_users);
        assert_eq!(expected_users, inserted_users);
    }

    #[test]
    fn insert_with_defaults_not_provided() {
        use self::users::table as users;
        let connection = connection();
        connection.execute("CREATE TABLE users (
            id SERIAL PRIMARY KEY,
            name VARCHAR NOT NULL,
            hair_color VARCHAR NOT NULL DEFAULT 'Green'
        )").unwrap();
        let new_users = vec![
            BaldUser { name: "Sean".to_string() },
            BaldUser { name: "Tess".to_string() },
        ];
        let inserted_users: Vec<_> = connection.insert(&users, new_users).unwrap().collect();

        let expected_users = vec![
            User { id: 1, name: "Sean".to_string(), hair_color: Some("Green".to_string()) },
            User { id: 2, name: "Tess".to_string(), hair_color: Some("Green".to_string()) },
        ];
        let actual_users: Vec<_> = connection.query_all(&users).unwrap().collect();

        assert_eq!(expected_users, actual_users);
        assert_eq!(expected_users, inserted_users);
    }

    #[derive(Debug, PartialEq, Eq)]
    struct NewUser {
        name: String,
        hair_color: Option<String>,
    }

    struct BaldUser {
        name: String,
    }

    impl NewUser {
        fn new(name: &str, hair_color: Option<&str>) -> Self {
            NewUser {
                name: name.to_string(),
                hair_color: hair_color.map(|s| s.to_string()),
            }
        }
    }

    insertable! {
        NewUser -> users {
            name -> String,
            hair_color -> Option<String>,
        }
    }

    queriable! {
        NewUser {
            name -> String,
            hair_color -> Option<String>,
        }
    }

    insertable! {
        BaldUser -> users {
            name -> String,
        }
    }

    fn setup_users_table(connection: &Connection) {
        connection.execute("CREATE TABLE users (
            id SERIAL PRIMARY KEY,
            name VARCHAR NOT NULL,
            hair_color VARCHAR
        )").unwrap();
    }

    fn setup_posts_table(connection: &Connection) {
        connection.execute("CREATE TABLE posts (
            id SERIAL PRIMARY KEY,
            user_id INTEGER NOT NULL,
            title VARCHAR NOT NULL
        )").unwrap();
    }
}
<|endoftext|>


<commit_before>#![feature(libc)]

extern crate libc;
extern crate "glib-2_0-sys" as glib;

use libc::{
    c_char
};

use glib::types::{
    gboolean,
};

use glib::list::GList;

extern "C" {
    pub fn notify_init(app_name: *const c_char) -> gboolean;
    pub fn notify_uninit();
    pub fn notify_is_initted() -> gboolean;

    pub fn notify_get_app_name() -> *const c_char;
    pub fn notify_set_app_name(app_name: *const c_char);

    pub fn notify_get_server_caps() -> *mut GList;
}
<commit_msg>Add notify_get_server_info<commit_after>#![feature(libc)]

extern crate libc;
extern crate "glib-2_0-sys" as glib;

use libc::{
    c_char
};

use glib::types::{
    gboolean,
};

use glib::list::GList;

extern "C" {
    pub fn notify_init(app_name: *const c_char) -> gboolean;
    pub fn notify_uninit();
    pub fn notify_is_initted() -> gboolean;

    pub fn notify_get_app_name() -> *const c_char;
    pub fn notify_set_app_name(app_name: *const c_char);

    pub fn notify_get_server_caps() -> *mut GList;

    pub fn notify_get_server_info(ret_name: *mut *mut c_char,
                                  ret_vendor: *mut *mut c_char,
                                  ret_version: *mut *mut c_char,
                                  ret_spec_version: *mut *mut c_char);
}
<|endoftext|>


<commit_before>#![crate_id = "curl"]
#![feature(macro_rules)]
#![feature(phase)]

extern crate libc;

#[phase(plugin, link)]
extern crate log;

pub use ffi::easy::ProgressCb;
pub use ffi::err::ErrCode;

// Version accessors
pub use ffi::version::{
  Version,
  version,
  version_info,
  Protocols
};

mod ffi;
pub mod http;

#[cfg(test)]
mod test;
<commit_msg>crate_id => crate_name<commit_after>#![crate_name = "curl"]
#![feature(macro_rules)]
#![feature(phase)]

extern crate libc;

#[phase(plugin, link)]
extern crate log;

pub use ffi::easy::ProgressCb;
pub use ffi::err::ErrCode;

// Version accessors
pub use ffi::version::{
  Version,
  version,
  version_info,
  Protocols
};

mod ffi;
pub mod http;

#[cfg(test)]
mod test;
<|endoftext|>


<commit_before>//! Helpers for writing Alfred XML output

#![warn(missing_doc)]

use std::io;
use std::io::BufferedWriter;
use std::str;

/// Representation of an `<item>`
#[deriving(PartialEq,Eq,Clone)]
pub struct Item<'a> {
    /// Identifier for the results. If given, must be unique among items, and is used for
    /// prioritizing feedback results based on usage. If blank, Alfred uses a UUID and does
    /// not learn from the results.
    pub uid: Option<str::MaybeOwned<'a>>,
    /// The value that is passed to the next portion of the workflow when this item
    /// is selected.
    pub arg: Option<str::MaybeOwned<'a>>,
    /// What type of result this is, if any.
    pub type_: Option<ItemType>,
    /// Whether or not the result item is 'valid'. If `false`, `autocomplete` may be used.
    pub valid: bool,
    /// Autocomplete data for valid=false items. When this item is selected, the autocomplete
    /// value is inserted into the Alfred window.
    pub autocomplete: Option<str::MaybeOwned<'a>>,

    /// Title for the item
    pub title: str::MaybeOwned<'a>,
    /// Subtitle for the item
    pub subtitle: Option<str::MaybeOwned<'a>>,
    /// Icon for the item
    pub icon: Option<Icon<'a>>
}

impl<'a> Item<'a> {
    /// Returns a new Item with the given title
    pub fn new<S: str::IntoMaybeOwned<'a>>(title: S) -> Item<'a> {
        Item {
            uid: None,
            arg: None,
            type_: None,
            valid: true,
            autocomplete: None,
            title: title.into_maybe_owned(),
            subtitle: None,
            icon: None
        }
    }
}

/// Item icons
#[deriving(PartialEq,Eq,Clone)]
pub enum Icon<'a> {
    /// Path to an image file on disk relative to the workflow directory
    PathIcon(str::MaybeOwned<'a>),
    /// Path to a file whose icon will be used
    FileIcon(str::MaybeOwned<'a>),
    /// UTI for a file type to use (e.g. public.folder)
    FileType(str::MaybeOwned<'a>)
}

/// Item types
#[deriving(PartialEq,Eq,Clone)]
pub enum ItemType {
    /// Type representing a file
    FileItemType
}

impl<'a> Item<'a> {
    /// Writes the XML fragment representing the Item to the Writer
    pub fn write_xml(&self, w: &mut io::Writer, indent: uint) -> io::IoResult<()> {
        fn write_indent(w: &mut io::Writer, indent: uint) -> io::IoResult<()> {
            for _ in range(0, indent) {
                try!(w.write_str("    "));
            }
            Ok(())
        }

        let mut w = BufferedWriter::with_capacity(512, w);

        try!(write_indent(&mut w, indent));
        try!(w.write_str("<item"));
        match self.uid {
            None => (),
            Some(ref uid) => {
                try!(write!(&mut w, r#" uid="{}""#, encode_entities(uid.as_slice())));
            }
        }
        match self.arg {
            None => (),
            Some(ref arg) => {
                try!(write!(&mut w, r#" arg="{}""#, encode_entities(arg.as_slice())));
            }
        }
        match self.type_ {
            None => (),
            Some(FileItemType) => {
                try!(w.write_str(r#" type="file""#));
            }
        }
        try!(write!(&mut w, r#" valid="{}""#, if self.valid { "yes" } else { "no" }));
        match self.autocomplete {
            None => (),
            Some(ref auto) => {
                try!(write!(&mut w, r#" autocomplete="{}""#, encode_entities(auto.as_slice())));
            }
        }
        try!(w.write_str(">\n"));

        try!(write_indent(&mut w, indent+1));
        try!(write!(&mut w, "<title>{}</title>\n", encode_entities(self.title.as_slice())));

        match self.subtitle {
            None => (),
            Some(ref s) => {
                try!(write_indent(&mut w, indent+1));
                try!(write!(&mut w, "<subtitle>{}</subtitle>\n", encode_entities(s.as_slice())));
            }
        }

        match self.icon {
            None => (),
            Some(ref icon) => {
                try!(write_indent(&mut w, indent+1));
                match *icon {
                    PathIcon(ref s) => {
                        try!(write!(&mut w, "<icon>{}</icon>\n", encode_entities(s.as_slice())));
                    }
                    FileIcon(ref s) => {
                        try!(write!(&mut w, "<icon type=\"fileicon\">{}</icon>\n",
                                      encode_entities(s.as_slice())));
                    }
                    FileType(ref s) => {
                        try!(write!(&mut w, "<icon type=\"filetype\">{}</icon>\n",
                                      encode_entities(s.as_slice())));
                    }
                }
            }
        }

        try!(write_indent(&mut w, indent));
        try!(w.write_str("</item>\n"));

        try!(w.flush());
        Ok(())
    }
}

fn encode_entities<'a>(s: &'a str) -> str::MaybeOwned<'a> {
    fn encode_entity(c: char) -> Option<&'static str> {
        Some(match c {
            '<' => "<",
            '>' => ">",
            '"' => """,
            '&' => "&",
            '\0'...'\x08' |
            '\x0B'...'\x0C' |
            '\x0E'...'\x1F' |
            '\uFFFE' | '\uFFFF' => {
                // these are all invalid characters in XML
                "\uFFFD"
            }
            _ => return None
        })
    }

    if s.chars().any(|c| encode_entity(c).is_some()) {
        let mut res = String::with_capacity(s.len());
        for c in s.chars() {
            match encode_entity(c) {
                Some(ent) => res.push_str(ent),
                None => res.push(c)
            }
        }
        str::Owned(res)
    } else {
        str::Slice(s)
    }
}
<commit_msg>Add helper type XMLWriter<commit_after>//! Helpers for writing Alfred XML output
//!
//! # Example
//!
//! ```
//! extern crate alfred;
//!
//! use std::io;
//!
//! fn write_items() -> io::IoResult<()> {
//!     let mut xmlw = try!(alfred::XMLWriter::new(io::stdout()));
//!
//!     let item1 = alfred::Item::new("Item 1");
//!     let item2 = alfred::Item {
//!         subtitle: Some("Subtitle".into_maybe_owned()),
//!         ..alfred::Item::new("Item 2")
//!     };
//!     let item3 = alfred::Item {
//!         arg: Some("Argument".into_maybe_owned()),
//!         subtitle: Some("Subtitle".into_maybe_owned()),
//!         icon: Some(alfred::FileType("public.folder".into_maybe_owned())),
//!         ..alfred::Item::new("Item 3")
//!     };
//!
//!     try!(xmlw.write_item(&item1));
//!     try!(xmlw.write_item(&item2));
//!     try!(xmlw.write_item(&item3));
//!
//!     xmlw.close()
//! }
//!
//! fn main() {
//!     match write_items() {
//!         Ok(()) => {},
//!         Err(err) => {
//!             let _ = writeln!(io::stderr(), "Error writing items: {}", err);
//!         }
//!     }
//! }
//! ```

#![feature(if_let)]
#![warn(missing_doc)]

use std::io;
use std::io::BufferedWriter;
use std::str;

/// Representation of an `<item>`
#[deriving(PartialEq,Eq,Clone)]
pub struct Item<'a> {
    /// Identifier for the results. If given, must be unique among items, and is used for
    /// prioritizing feedback results based on usage. If blank, Alfred uses a UUID and does
    /// not learn from the results.
    pub uid: Option<str::MaybeOwned<'a>>,
    /// The value that is passed to the next portion of the workflow when this item
    /// is selected.
    pub arg: Option<str::MaybeOwned<'a>>,
    /// What type of result this is, if any.
    pub type_: Option<ItemType>,
    /// Whether or not the result item is 'valid'. If `false`, `autocomplete` may be used.
    pub valid: bool,
    /// Autocomplete data for valid=false items. When this item is selected, the autocomplete
    /// value is inserted into the Alfred window.
    pub autocomplete: Option<str::MaybeOwned<'a>>,

    /// Title for the item
    pub title: str::MaybeOwned<'a>,
    /// Subtitle for the item
    pub subtitle: Option<str::MaybeOwned<'a>>,
    /// Icon for the item
    pub icon: Option<Icon<'a>>
}

impl<'a> Item<'a> {
    /// Returns a new Item with the given title
    pub fn new<S: str::IntoMaybeOwned<'a>>(title: S) -> Item<'a> {
        Item {
            uid: None,
            arg: None,
            type_: None,
            valid: true,
            autocomplete: None,
            title: title.into_maybe_owned(),
            subtitle: None,
            icon: None
        }
    }
}

/// Item icons
#[deriving(PartialEq,Eq,Clone)]
pub enum Icon<'a> {
    /// Path to an image file on disk relative to the workflow directory
    PathIcon(str::MaybeOwned<'a>),
    /// Path to a file whose icon will be used
    FileIcon(str::MaybeOwned<'a>),
    /// UTI for a file type to use (e.g. public.folder)
    FileType(str::MaybeOwned<'a>)
}

/// Item types
#[deriving(PartialEq,Eq,Clone)]
pub enum ItemType {
    /// Type representing a file
    FileItemType
}

/// Helper struct used to manage the XML serialization of `Item`s
///
/// When the `XMLWriter` is first created, the XML header is immediately
/// written. When the `XMLWriter` is dropped, the XML footer is written.
///
/// Any errors produced by writing the footer are silently ignored. The
/// `close()` method can be used to return any such error.
pub struct XMLWriter<'a, W: Writer + 'a> {
    w: W,
    last_err: Option<io::IoError>
}

impl<'a, W: Writer + 'a> XMLWriter<'a, W> {
    /// Returns a new `XMLWriter` that writes to the given `Writer`
    ///
    /// The XML header is written immediately.
    pub fn new(mut w: W) -> io::IoResult<XMLWriter<'a, W>> {
        match w.write_str("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<items>\n") {
            Ok(()) => {
                Ok(XMLWriter {
                    w: w,
                    last_err: None
                })
            }
            Err(err) => Err(err)
        }
    }

    /// Writes an `Item` to the underlying `Writer`
    ///
    /// If a previous write produced an error, any subsequent write will do
    /// nothing and return the same error. This is because the previous write
    /// may have partially completed, and attempting to write any more data
    /// will be unlikely to work properly.
    pub fn write_item(&mut self, item: &Item) -> io::IoResult<()> {
        if let Some(ref err) = self.last_err {
            return Err(err.clone());
        }
        let result = item.write_xml(&mut self.w, 1);
        if let Err(ref err) = result {
            self.last_err = Some(err.clone());
        }
        result
    }

    /// Consumes the `XMLWriter` and writes the XML footer
    ///
    /// This method can be used to get any error resulting from writing the
    /// footer. If this method is not used, the footer will be written when the
    /// `XMLWriter` is dropped and any error will be silently ignored.
    ///
    /// As with `write_item()`, if a previous invocation of `write_item()`
    /// returned an error, `close()` will return the same error without
    /// attempting to write the XML footer.
    pub fn close(mut self) -> io::IoResult<()> {
        if let Some(err) = self.last_err {
            return Err(err);
        }
        self.w.write_str("</items>\n")
    }
}

/// Writes a complete XML document representing the `Item`s to the `Writer`
pub fn write_items<W: Writer>(w: W, items: &[Item]) -> io::IoResult<()> {
    let mut xmlw = try!(XMLWriter::new(w));
    for item in items.iter() {
        try!(xmlw.write_item(item));
    }
    xmlw.close()
}

impl<'a> Item<'a> {
    /// Writes the XML fragment representing the `Item` to the `Writer`
    ///
    /// `XMLWriter` should be used instead if at all possible, in order to
    /// write the XML header/footer and maintain proper error discipline.
    pub fn write_xml(&self, w: &mut io::Writer, indent: uint) -> io::IoResult<()> {
        fn write_indent(w: &mut io::Writer, indent: uint) -> io::IoResult<()> {
            for _ in range(0, indent) {
                try!(w.write_str("    "));
            }
            Ok(())
        }

        let mut w = BufferedWriter::with_capacity(512, w);

        try!(write_indent(&mut w, indent));
        try!(w.write_str("<item"));
        match self.uid {
            None => (),
            Some(ref uid) => {
                try!(write!(&mut w, r#" uid="{}""#, encode_entities(uid.as_slice())));
            }
        }
        match self.arg {
            None => (),
            Some(ref arg) => {
                try!(write!(&mut w, r#" arg="{}""#, encode_entities(arg.as_slice())));
            }
        }
        match self.type_ {
            None => (),
            Some(FileItemType) => {
                try!(w.write_str(r#" type="file""#));
            }
        }
        try!(write!(&mut w, r#" valid="{}""#, if self.valid { "yes" } else { "no" }));
        match self.autocomplete {
            None => (),
            Some(ref auto) => {
                try!(write!(&mut w, r#" autocomplete="{}""#, encode_entities(auto.as_slice())));
            }
        }
        try!(w.write_str(">\n"));

        try!(write_indent(&mut w, indent+1));
        try!(write!(&mut w, "<title>{}</title>\n", encode_entities(self.title.as_slice())));

        match self.subtitle {
            None => (),
            Some(ref s) => {
                try!(write_indent(&mut w, indent+1));
                try!(write!(&mut w, "<subtitle>{}</subtitle>\n", encode_entities(s.as_slice())));
            }
        }

        match self.icon {
            None => (),
            Some(ref icon) => {
                try!(write_indent(&mut w, indent+1));
                match *icon {
                    PathIcon(ref s) => {
                        try!(write!(&mut w, "<icon>{}</icon>\n", encode_entities(s.as_slice())));
                    }
                    FileIcon(ref s) => {
                        try!(write!(&mut w, "<icon type=\"fileicon\">{}</icon>\n",
                                      encode_entities(s.as_slice())));
                    }
                    FileType(ref s) => {
                        try!(write!(&mut w, "<icon type=\"filetype\">{}</icon>\n",
                                      encode_entities(s.as_slice())));
                    }
                }
            }
        }

        try!(write_indent(&mut w, indent));
        try!(w.write_str("</item>\n"));

        try!(w.flush());
        Ok(())
    }
}

fn encode_entities<'a>(s: &'a str) -> str::MaybeOwned<'a> {
    fn encode_entity(c: char) -> Option<&'static str> {
        Some(match c {
            '<' => "<",
            '>' => ">",
            '"' => """,
            '&' => "&",
            '\0'...'\x08' |
            '\x0B'...'\x0C' |
            '\x0E'...'\x1F' |
            '\uFFFE' | '\uFFFF' => {
                // these are all invalid characters in XML
                "\uFFFD"
            }
            _ => return None
        })
    }

    if s.chars().any(|c| encode_entity(c).is_some()) {
        let mut res = String::with_capacity(s.len());
        for c in s.chars() {
            match encode_entity(c) {
                Some(ent) => res.push_str(ent),
                None => res.push(c)
            }
        }
        str::Owned(res)
    } else {
        str::Slice(s)
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Corey Farwell
// Copyright 2015 Contributors of github.com/huonw/crates.io-graph
//
// 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.

//! Library for retrieving and interacting with the [crates.io index].
//!
//! [crates.io index]: https://github.com/rust-lang/crates.io-index
//!
//! ## Examples
//!
//! ```rust
//! extern crate crates_index;
//!
//! let index = crates_index::Index::new("_index");
//! if !index.exists() {
//!    index.retrieve().expect("Could not fetch crates.io index");
//! }
//! for crate_ in index.crates() {
//!    let latest_version = crate_.latest_version();
//!    println!("crate name: {}", latest_version.name());
//!    println!("crate version: {}", latest_version.version());
//! }
//! ```

use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs;
use std::io::{BufRead, BufReader};
use std::iter;
use std::path::{Path, PathBuf};

#[macro_use]
extern crate error_chain;
extern crate git2;
extern crate glob;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;

error_chain! {
    foreign_links {
        Git(git2::Error);
    }
}

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";

/// A single version of a crate published to the index
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Version {
    name: String,
    vers: String,
    deps: Vec<Dependency>,
    cksum: String,
    features: HashMap<String, Vec<String>>,
    yanked: bool,
}

impl Version {
    /// Name of the crate
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Name of this version
    pub fn version(&self) -> &str {
        &self.vers
    }

    /// Dependencies for this version
    pub fn dependencies(&self) -> &[Dependency] {
        &self.deps
    }

    /// Checksum of the package for this version
    pub fn checksum(&self) -> &str {
        &self.cksum
    }

    pub fn features(&self) -> &HashMap<String, Vec<String>> {
        &self.features
    }

    /// Whether this version was [yanked](http://doc.crates.io/crates-io.html#cargo-yank) from the
    /// index
    pub fn is_yanked(&self) -> bool {
        self.yanked
    }
}

/// A single dependency of a specific crate version
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Dependency {
    name: String,
    req: String,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<String>,
    kind: Option<String>,
    package: Option<String>,
}

impl Dependency {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn requirement(&self) -> &str {
        &self.req
    }

    pub fn features(&self) -> &[String] {
        &self.features
    }

    pub fn is_optional(&self) -> bool {
        self.optional
    }

    pub fn has_default_features(&self) -> bool {
        self.default_features
    }

    pub fn target(&self) -> Option<&str> {
        match self.target {
            Some(ref s) => Some(s),
            None => None,
        }
    }

    pub fn kind(&self) -> Option<&str> {
        match self.kind {
            Some(ref s) => Some(s),
            None => None,
        }
    }

    pub fn package(&self) -> Option<&str> {
        match self.package {
            Some(ref s) => Some(s),
            None => None,
        }
    }

    /// Returns the name of the crate providing the dependency.
    /// This is equivalent to `name()` unless `self.package()`
    /// is not `None`, in which case it's equal to `self.package()`.
    ///
    /// Basically, you can define a dependency in your `Cargo.toml`
    /// like this:
    ///
    /// ```toml
    /// serde_lib = {version = "1", package = "serde"}
    /// ```
    ///
    /// ...which means that it uses the crate `serde` but imports
    /// it under the name `serde_lib`.
    pub fn crate_name(&self) -> &str {
        match self.package {
            Some(ref s) => s,
            None => self.name(),
        }
    }
}

/// Constructed from `Index::crates`
pub struct Crates(CrateIndexPaths);

impl Iterator for Crates {
    type Item = Crate;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|p| Crate::new(&p))
    }
}

/// Constructed from `Index::crate_index_paths`
pub struct CrateIndexPaths(iter::Chain<glob::Paths, glob::Paths>);

impl CrateIndexPaths {
    fn new<P: AsRef<Path>>(path: P) -> CrateIndexPaths {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;
        let path = path.as_ref();

        let glob_pattern = format!("{}/*/*/*", path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        CrateIndexPaths(index_paths1.chain(index_paths2))
    }
}

impl Iterator for CrateIndexPaths {
    type Item = PathBuf;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|glob_result| glob_result.unwrap())
    }
}

/// Wrapper around managing the crates.io-index git repository
#[derive(Debug, Clone, PartialEq)]
pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new<P: Into<PathBuf>>(path: P) -> Index {
        Index { path: path.into() }
    }

    /// Determines if a crates.io repository exists at `self.path`
    pub fn exists(&self) -> bool {
        git2::Repository::discover(&self.path)
            .map(|repository| {
                repository
                    .find_remote("origin")
                    .map(|remote| remote.url() == Some(INDEX_GIT_URL))
                    .unwrap_or(false)
            })
            .unwrap_or(false)
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve(&self) -> Result<()> {
        let _ = git2::Repository::clone(INDEX_GIT_URL, &self.path)?;
        Ok(())
    }

    /// Assumes the index already exists at `self.path`, and updates it
    pub fn update(&self) -> Result<()> {
        debug_assert!(self.exists());
        let repo = git2::Repository::discover(&self.path)?;
        let mut origin_remote = repo.find_remote("origin")?;
        origin_remote.fetch(&["master"], None, None)?;
        let oid = repo.refname_to_id("refs/remotes/origin/master")?;
        let object = repo.find_object(oid, None).unwrap();
        repo.reset(&object, git2::ResetType::Hard, None)?;
        Ok(())
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve_or_update(&self) -> Result<()> {
        if self.exists() {
            self.update()
        } else {
            self.retrieve()
        }
    }

    /// Retrieve a single crate by name (case insensitive) from the index
    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        self.crate_index_paths()
            .find(|path| {
                      path.file_name()
                          .and_then(OsStr::to_str)
                          .map(|file_name| file_name.eq_ignore_ascii_case(crate_name))
                          .unwrap_or(false)
                  })
            .map(|p| Crate::new(&p))
    }

    /// Retrieve an iterator over all the crates in the index
    pub fn crates(&self) -> Crates {
        Crates(self.crate_index_paths())
    }

    /// Returns all the crate index file paths in the index
    pub fn crate_index_paths(&self) -> CrateIndexPaths {
        CrateIndexPaths::new(self.path.clone()) // TODO: remove this clone
    }

    /// Get the index directory.
    pub fn path(&self) -> &Path {
        &self.path
    }
}

/// A single crate that contains many published versions
#[derive(Serialize, Debug)]
pub struct Crate {
    versions: Vec<Version>,
}

impl Crate {
    pub fn new<P: AsRef<Path>>(index_path: P) -> Crate {
        let index_path = index_path.as_ref();
        let mut versions = vec![];
        let file = fs::File::open(&index_path).unwrap();
        for line in BufReader::new(file).lines() {
            let version: Version = serde_json::from_str(&line.unwrap()).unwrap();
            versions.push(version);
        }
        Crate { versions: versions }
    }

    /// Published versions of this crate sorted chronologically by date published
    pub fn versions(&self) -> &[Version] {
        &self.versions
    }

    pub fn earliest_version(&self) -> &Version {
        &self.versions[0]
    }

    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len() - 1]
    }

    pub fn name(&self) -> &str {
        self.latest_version().name()
    }
}

#[cfg(test)]
mod test {
    use super::Index;
    extern crate tempdir;
    use self::tempdir::TempDir;

    #[test]
    fn test_dependencies() {
        let tmp_dir = TempDir::new("test1").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        // let crate_ = index.crates().nth(0).expect("could not find a crate in the index");
        let crate_ = index.crate_("sval").expect("Could not find the crate libnotify in the index");
        let _ = format!("supports debug {:?}", crate_);

        let version = crate_.versions().iter().find(|v| v.version() == "0.0.1")
            .expect("Version 0.0.1 of sval does not exist?");
        let dep_with_package_name = version.dependencies().iter().find(|d| d.name() == "serde_lib")
            .expect("sval does not have expected dependency?");
        assert_ne!(dep_with_package_name.name(), dep_with_package_name.package().unwrap());
        assert_eq!(dep_with_package_name.crate_name(), dep_with_package_name.package().unwrap());
    }

    #[test]
    fn test_retrieve_or_update() {
        let tmp_dir = TempDir::new("test2").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
    }

    #[test]
    fn test_exists() {
        let tmp_dir = TempDir::new("test3").unwrap();

        let index = Index::new(tmp_dir.path());
        assert!(!index.exists());
        index.retrieve().unwrap();
        assert!(index.exists());
    }
}
<commit_msg>Implement Deserialize and Clone for Crate<commit_after>// Copyright 2015 Corey Farwell
// Copyright 2015 Contributors of github.com/huonw/crates.io-graph
//
// 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.

//! Library for retrieving and interacting with the [crates.io index].
//!
//! [crates.io index]: https://github.com/rust-lang/crates.io-index
//!
//! ## Examples
//!
//! ```rust
//! extern crate crates_index;
//!
//! let index = crates_index::Index::new("_index");
//! if !index.exists() {
//!    index.retrieve().expect("Could not fetch crates.io index");
//! }
//! for crate_ in index.crates() {
//!    let latest_version = crate_.latest_version();
//!    println!("crate name: {}", latest_version.name());
//!    println!("crate version: {}", latest_version.version());
//! }
//! ```

use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs;
use std::io::{BufRead, BufReader};
use std::iter;
use std::path::{Path, PathBuf};

#[macro_use]
extern crate error_chain;
extern crate git2;
extern crate glob;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;

error_chain! {
    foreign_links {
        Git(git2::Error);
    }
}

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";

/// A single version of a crate published to the index
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Version {
    name: String,
    vers: String,
    deps: Vec<Dependency>,
    cksum: String,
    features: HashMap<String, Vec<String>>,
    yanked: bool,
}

impl Version {
    /// Name of the crate
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Name of this version
    pub fn version(&self) -> &str {
        &self.vers
    }

    /// Dependencies for this version
    pub fn dependencies(&self) -> &[Dependency] {
        &self.deps
    }

    /// Checksum of the package for this version
    pub fn checksum(&self) -> &str {
        &self.cksum
    }

    pub fn features(&self) -> &HashMap<String, Vec<String>> {
        &self.features
    }

    /// Whether this version was [yanked](http://doc.crates.io/crates-io.html#cargo-yank) from the
    /// index
    pub fn is_yanked(&self) -> bool {
        self.yanked
    }
}

/// A single dependency of a specific crate version
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Dependency {
    name: String,
    req: String,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<String>,
    kind: Option<String>,
    package: Option<String>,
}

impl Dependency {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn requirement(&self) -> &str {
        &self.req
    }

    pub fn features(&self) -> &[String] {
        &self.features
    }

    pub fn is_optional(&self) -> bool {
        self.optional
    }

    pub fn has_default_features(&self) -> bool {
        self.default_features
    }

    pub fn target(&self) -> Option<&str> {
        match self.target {
            Some(ref s) => Some(s),
            None => None,
        }
    }

    pub fn kind(&self) -> Option<&str> {
        match self.kind {
            Some(ref s) => Some(s),
            None => None,
        }
    }

    pub fn package(&self) -> Option<&str> {
        match self.package {
            Some(ref s) => Some(s),
            None => None,
        }
    }

    /// Returns the name of the crate providing the dependency.
    /// This is equivalent to `name()` unless `self.package()`
    /// is not `None`, in which case it's equal to `self.package()`.
    ///
    /// Basically, you can define a dependency in your `Cargo.toml`
    /// like this:
    ///
    /// ```toml
    /// serde_lib = {version = "1", package = "serde"}
    /// ```
    ///
    /// ...which means that it uses the crate `serde` but imports
    /// it under the name `serde_lib`.
    pub fn crate_name(&self) -> &str {
        match self.package {
            Some(ref s) => s,
            None => self.name(),
        }
    }
}

/// Constructed from `Index::crates`
pub struct Crates(CrateIndexPaths);

impl Iterator for Crates {
    type Item = Crate;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|p| Crate::new(&p))
    }
}

/// Constructed from `Index::crate_index_paths`
pub struct CrateIndexPaths(iter::Chain<glob::Paths, glob::Paths>);

impl CrateIndexPaths {
    fn new<P: AsRef<Path>>(path: P) -> CrateIndexPaths {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;
        let path = path.as_ref();

        let glob_pattern = format!("{}/*/*/*", path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        CrateIndexPaths(index_paths1.chain(index_paths2))
    }
}

impl Iterator for CrateIndexPaths {
    type Item = PathBuf;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|glob_result| glob_result.unwrap())
    }
}

/// Wrapper around managing the crates.io-index git repository
#[derive(Debug, Clone, PartialEq)]
pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new<P: Into<PathBuf>>(path: P) -> Index {
        Index { path: path.into() }
    }

    /// Determines if a crates.io repository exists at `self.path`
    pub fn exists(&self) -> bool {
        git2::Repository::discover(&self.path)
            .map(|repository| {
                repository
                    .find_remote("origin")
                    .map(|remote| remote.url() == Some(INDEX_GIT_URL))
                    .unwrap_or(false)
            })
            .unwrap_or(false)
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve(&self) -> Result<()> {
        let _ = git2::Repository::clone(INDEX_GIT_URL, &self.path)?;
        Ok(())
    }

    /// Assumes the index already exists at `self.path`, and updates it
    pub fn update(&self) -> Result<()> {
        debug_assert!(self.exists());
        let repo = git2::Repository::discover(&self.path)?;
        let mut origin_remote = repo.find_remote("origin")?;
        origin_remote.fetch(&["master"], None, None)?;
        let oid = repo.refname_to_id("refs/remotes/origin/master")?;
        let object = repo.find_object(oid, None).unwrap();
        repo.reset(&object, git2::ResetType::Hard, None)?;
        Ok(())
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve_or_update(&self) -> Result<()> {
        if self.exists() {
            self.update()
        } else {
            self.retrieve()
        }
    }

    /// Retrieve a single crate by name (case insensitive) from the index
    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        self.crate_index_paths()
            .find(|path| {
                      path.file_name()
                          .and_then(OsStr::to_str)
                          .map(|file_name| file_name.eq_ignore_ascii_case(crate_name))
                          .unwrap_or(false)
                  })
            .map(|p| Crate::new(&p))
    }

    /// Retrieve an iterator over all the crates in the index
    pub fn crates(&self) -> Crates {
        Crates(self.crate_index_paths())
    }

    /// Returns all the crate index file paths in the index
    pub fn crate_index_paths(&self) -> CrateIndexPaths {
        CrateIndexPaths::new(self.path.clone()) // TODO: remove this clone
    }

    /// Get the index directory.
    pub fn path(&self) -> &Path {
        &self.path
    }
}

/// A single crate that contains many published versions
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Crate {
    versions: Vec<Version>,
}

impl Crate {
    pub fn new<P: AsRef<Path>>(index_path: P) -> Crate {
        let index_path = index_path.as_ref();
        let mut versions = vec![];
        let file = fs::File::open(&index_path).unwrap();
        for line in BufReader::new(file).lines() {
            let version: Version = serde_json::from_str(&line.unwrap()).unwrap();
            versions.push(version);
        }
        Crate { versions: versions }
    }

    /// Published versions of this crate sorted chronologically by date published
    pub fn versions(&self) -> &[Version] {
        &self.versions
    }

    pub fn earliest_version(&self) -> &Version {
        &self.versions[0]
    }

    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len() - 1]
    }

    pub fn name(&self) -> &str {
        self.latest_version().name()
    }
}

#[cfg(test)]
mod test {
    use super::Index;
    extern crate tempdir;
    use self::tempdir::TempDir;

    #[test]
    fn test_dependencies() {
        let tmp_dir = TempDir::new("test1").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        // let crate_ = index.crates().nth(0).expect("could not find a crate in the index");
        let crate_ = index.crate_("sval").expect("Could not find the crate libnotify in the index");
        let _ = format!("supports debug {:?}", crate_);

        let version = crate_.versions().iter().find(|v| v.version() == "0.0.1")
            .expect("Version 0.0.1 of sval does not exist?");
        let dep_with_package_name = version.dependencies().iter().find(|d| d.name() == "serde_lib")
            .expect("sval does not have expected dependency?");
        assert_ne!(dep_with_package_name.name(), dep_with_package_name.package().unwrap());
        assert_eq!(dep_with_package_name.crate_name(), dep_with_package_name.package().unwrap());
    }

    #[test]
    fn test_retrieve_or_update() {
        let tmp_dir = TempDir::new("test2").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
    }

    #[test]
    fn test_exists() {
        let tmp_dir = TempDir::new("test3").unwrap();

        let index = Index::new(tmp_dir.path());
        assert!(!index.exists());
        index.retrieve().unwrap();
        assert!(index.exists());
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
use std::collections::hashmap::HashMap;
use std::vec::MoveItems;

#[cfg(test)]
mod tests;

pub struct IrcMessage {
    pub tags: HashMap<String, String>,
    pub prefix: Option<String>,
    pub command: Option<String>,
    pub params: Vec<String>
}

impl IrcMessage {
    pub fn new_empty() -> IrcMessage {
        IrcMessage {
            tags: HashMap::new(),
            prefix: None,
            command: None,
            params: Vec::new()
        }
    }
}

fn find_after_n(string: &str, c: char, n: uint) -> Option<uint> {
    string.slice_from(n).find(c).map(|a| a + n)
}

fn is_white(c: &char) -> bool { *c == ' ' }
fn not_white(c: &char) -> bool { !is_white(c) }

fn strip<I: Iterator<char>>(iter: I) -> MoveItems<char> {
    let vec: Vec<char> = iter.skip_while(is_white).collect();
    vec.move_iter()
}

pub fn parse(line: &str) -> Result<IrcMessage, ()> {
    let mut message = IrcMessage::new_empty();
    let mut chars = line.chars().peekable();
    // Tags
    if chars.peek() == Some(&'@') {
        let mut tags = chars.by_ref().skip(1).take_while(not_white);
        loop {
            let mut tag = tags.by_ref().take_while(|&c| c != ';').peekable();
            if tag.peek() == None { break; }
            let name = tag.by_ref().take_while(|&c| c != '=').collect();
            let mut rest = tag.peekable();
            let value = if rest.is_empty() {
                "true".to_string()
            } else {
                rest.collect()
            };
            message.tags.insert(name, value);
        }
    }
    let mut chars = chars.peekable();
    if chars.is_empty() { return Err(()); }
    let mut chars = strip(chars).peekable();

    // Prefix
    if chars.peek() == Some(&':') {
        let prefix = chars.by_ref().skip(1).take_while(not_white).collect();
        message.prefix = Some(prefix);
    }

    let mut chars = chars.peekable();
    if chars.is_empty() { return Err(()) }
    let mut chars = strip(chars);

    // Command
    let command = chars.by_ref().take_while(not_white).collect();
    message.command = Some(command);
    let mut chars = strip(chars);

    // Params
    loop {
        let mut chars = chars.by_ref().skip_while(is_white).peekable();
        match chars.peek() {
            None => {
                println!("breaking on none");
                break; }
            Some(&':') => {
                message.params.push(chars.skip(1).collect());
                println!("breaking on done");
                break;
            }
            _ => {
                println!("\nbefore");
                chars.by_ref().inspect(|&c| print!("{}", c) );
                message.params.push(chars.by_ref().take_while(not_white).collect());
            }
        }
    }

    Ok(message)
}
<commit_msg>cleanup + comments<commit_after>#![allow(dead_code)]
use std::collections::hashmap::HashMap;
use std::vec::MoveItems;

#[cfg(test)]
mod tests;

pub struct IrcMessage {
    pub tags: HashMap<String, String>,
    pub prefix: Option<String>,
    pub command: Option<String>,
    pub params: Vec<String>
}

impl IrcMessage {
    pub fn new_empty() -> IrcMessage {
        IrcMessage {
            tags: HashMap::new(),
            prefix: None,
            command: None,
            params: Vec::new()
        }
    }
}

fn find_after_n(string: &str, c: char, n: uint) -> Option<uint> {
    string.slice_from(n).find(c).map(|a| a + n)
}

fn is_white(c: &char) -> bool { *c == ' ' }
fn not_white(c: &char) -> bool { !is_white(c) }

// Strips whitespace off an iterator.  It also recollects the
// characters in order to keep rustc from blowing itself up.
// github.com/rust-lang/rust/issues/16232
fn strip<I: Iterator<char>>(iter: I) -> MoveItems<char> {
    let vec: Vec<char> = iter.skip_while(is_white).collect();
    vec.move_iter()
}

pub fn parse(line: &str) -> Result<IrcMessage, ()> {
    let mut message = IrcMessage::new_empty();
    let mut chars = line.chars().peekable();
    // Tags
    if chars.peek() == Some(&'@') {
        // Tags are from the @ to the first space character.
        let mut tags = chars.by_ref().skip(1).take_while(not_white);
        loop {
            // Tags are seperated by semicolons
            let mut tag = tags.by_ref().take_while(|&c| c != ';').peekable();
            if tag.peek() == None { break; }
            // A tag might have a '=' seperating key and value pairs
            let name = tag.by_ref().take_while(|&c| c != '=').collect();
            let mut rest = tag.peekable();
            let value = if rest.is_empty() {
                // True is the default value if one is not provided.
                "true".to_string()
            } else {
                rest.collect()
            };
            message.tags.insert(name, value);
        }
    }

    // An empty iterator at this point is a parsing failure
    let mut chars = strip(chars).peekable();
    if chars.is_empty() { return Err(()); }

    // Prefix
    if chars.peek() == Some(&':') {
        let prefix = chars.by_ref().skip(1).take_while(not_white).collect();
        message.prefix = Some(prefix);
    }

    let mut chars = strip(chars).peekable();
    if chars.is_empty() { return Err(()) }

    // Command
    let command = chars.by_ref().take_while(not_white).collect();
    message.command = Some(command);
    let mut chars = strip(chars).peekable();

    // Params
    loop {
        match chars.peek() {
            None => { break; }
            Some(&':') => {
                // The rest of the string
                message.params.push(chars.skip(1).collect());
                break;
            }
            _ => {
                message.params.push(chars.by_ref().take_while(not_white).collect());
                chars = strip(chars).peekable();
            }
        }
    }

    Ok(message)
}
<|endoftext|>


<commit_before>extern crate regex;

pub mod score;
pub mod search;
pub mod configuration;
pub mod renderer;
<commit_msg>Removes regex import<commit_after>pub mod score;
pub mod search;
pub mod configuration;
pub mod renderer;
<|endoftext|>