Repository: AlexPikalov/cdrs (language: rust)

Issue:
Protocol parsing issues on many inserts
Given the schema
```sql
CREATE KEYSPACE meow WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
USE meow;
CREATE TABLE kittehz (id UUID PRIMARY KEY, name VARCHAR, stuff BOOLEAN);
```

running the latest Cassandra version from Docker on macOS HS
```
docker run --name some-cassandra -d -p 9042:9042 cassandra
```

```
cqlsh:meow> SHOW VERSION;
[cqlsh 5.0.1 | Cassandra 3.11.2 | CQL spec 3.4.4 | Native protocol v4]
```

executing the code
```rust
extern crate cdrs;

use cdrs::client::CDRS;
use cdrs::authenticators::NoneAuthenticator;
use cdrs::transport::TransportTcp;
use cdrs::query::QueryBuilder;
use cdrs::compression::Compression;
use std::error::Error;


fn main() -> Result<(), Box<Error>> {
    let authenticator = NoneAuthenticator;
    let addr = "127.0.0.1:9042";
    let tcp_transport = TransportTcp::new(addr).unwrap();

    // pass authenticator and transport into CDRS' constructor
    let client = CDRS::new(tcp_transport, authenticator);

    // start session without compression
    let session = client.start(Compression::None)?;

    match session.query(QueryBuilder::new("USE meow").finalize(), false, false) {
        Err(ref err) => panic!("cant use keyspace {:?}", err),
        Ok(_) => {},
    }

    for i in 0..100_000 {
        let query = QueryBuilder::new(r#"
            INSERT INTO kittehz
            (id, name, stuff)
            VALUES
            (uuid(), 'a', false)
        "#).finalize();

        match session.query(query, false, false) {
            Ok(_) => {},
            Err(ref err) => panic!("cant insert {:?}", err),
        }
    }

    Ok(())
}
```

crashes the library after 15123 inserts, either entering unreachable code

```
➜  cdrs-bug git:(master) ✗ cargo run --release
   Compiling cdrs-bug v0.1.0 (file:///Users/ath/Desktop/cdrs-bug)
    Finished release [optimized] target(s) in 0.44s
     Running `target/release/cdrs-bug`
thread 'main' panicked at 'internal error: entered unreachable code', /Users/ath/.cargo/registry/src/github.com-1ecc6299db9ec823/cdrs-1.2.3/src/frame/mod.rs:322:18
note: Run with `RUST_BACKTRACE=1` for a backtrace.
```

or reporting an unexpected Cassandra version
```

➜  cdrs-bug git:(master) ✗ cargo run --release
    Finished release [optimized] target(s) in 0.02s
     Running `target/release/cdrs-bug`
thread 'main' panicked at 'Unexpected Cassandra version 0, either 4 or 132 is expected', /Users/ath/.cargo/registry/src/github.com-1ecc6299db9ec823/cdrs-1.2.3/src/frame/mod.rs:166:13
note: Run with `RUST_BACKTRACE=1` for a backtrace.
```

Looks like the parser is getting confused, reading from a wrong offset. I attached a Cargo module / project (what do you even call them?) that reproduces the issue on my machine™.

[cdrs-bug.tar.gz](https://github.com/AlexPikalov/cdrs/files/2006420/cdrs-bug.tar.gz)


Discussion / hints:

Fix patch:
diff --git a/.travis.yml b/.travis.yml
index 8d5af6a..8006d68 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -56,4 +56,4 @@ after_success:
   bash <(curl -s https://codecov.io/bash) &&
   rm -rf target/cov &&
   for file in target/debug/cdrs-*; do mkdir -p "target/coverall/$(basename $file)"; kcov --coveralls-id=$TRAVIS_JOB_ID --exclude-pattern=/.cargo,/usr/lib --verify "target/coverall/$(basename $file)" "$file"; done &&
-  echo "Uploaded code coverage"
+  echo "Uploaded code coverage"
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
index 72f37cf..2c07e53 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "cdrs"
-version = "1.2.3"
+version = "2.0.0-beta.1"
 authors = ["Alex Pikalov <alex.pikalov.khar@gmail.com>"]
 
 description = "Cassandra DB driver written in Rust"
@@ -30,6 +30,7 @@ rand = "0.4.1"
 snap = "0.2.3"
 time = "0.1.38"
 uuid = "0.6.3"
+cdrs_helpers_derive = {git = "https://github.com/AlexPikalov/cdrs-helpers-derive"}
 
 [dev-dependencies]
 env_logger = "0.4.3"
diff --git a/README.md b/README.md
index 9d1cd17..545564d 100644
--- a/README.md
+++ b/README.md
@@ -1,96 +1,52 @@
-# CDRS [![Build Status](https://travis-ci.org/AlexPikalov/cdrs.svg?branch=master)](https://travis-ci.org/AlexPikalov/cdrs) [![Build status](https://ci.appveyor.com/api/projects/status/sirj4flws6o0dvb7/branch/master?svg=true)](https://ci.appveyor.com/project/harrydevnull/cdrs/branch/master)
+# CDRS [![crates.io version](https://img.shields.io/crates/v/cdrs.svg)](https://crates.io/crates/cdrs) [![Build Status](https://travis-ci.org/AlexPikalov/cdrs.svg?branch=master)](https://travis-ci.org/AlexPikalov/cdrs) [![Build status](https://ci.appveyor.com/api/projects/status/sirj4flws6o0dvb7/branch/master?svg=true)](https://ci.appveyor.com/project/harrydevnull/cdrs/branch/master)
 
+CDRS is Apache **C**assandra **d**river written in pure **R**u**s**t. The driver implements all the features described in Cassandra binary protocol specification (versions 3 and 4).
 
-[![crates.io version](https://img.shields.io/crates/v/cdrs.svg)](https://crates.io/crates/cdrs)
-[![Join the chat at https://gitter.im/cdrs-rs/Lobby](https://badges.gitter.im/cdrs-rs/Lobby.svg)](https://gitter.im/cdrs-rs/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-[![Coverage Status](https://coveralls.io/repos/github/harrydevnull/cdrs/badge.svg?branch=master)](https://coveralls.io/github/harrydevnull/cdrs?branch=master)
-[![codecov](https://codecov.io/gh/harrydevnull/cdrs/branch/master/graph/badge.svg)](https://codecov.io/gh/harrydevnull/cdrs)
+### Describing Cassandra Cluster and starting new Session
 
+In order to start any communication with Cassandra cluster that requires authentication there should be provided a list of Cassandra nodes (IP addresses of machines where Cassandra is installed and included into a cluster). To get more details how to configure multinode cluster refer, for instance, to [DataStax documentation](https://docs.datastax.com/en/cassandra/3.0/cassandra/initialize/initTOC.html).
 
-**CDRS** is a native driver for [Apache Cassandra](http://cassandra.apache.org) written in [Rust](https://www.rust-lang.org).
-The motivation to write it in Rust is a lack of native one.
-Existing ones are bindings to C clients.
-
-[Documentation](https://docs.rs/cdrs)
-
-**CDRS** completely implements 4-th version of [Cassandra protocol](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec).
-Also it provides tools for [mapping results](#select-query-mapping-results)
-into Rust structures.
-
-## Content
-* [Creating new connection and authorization](#creating-new-connection-and-authorization)
-* [Creating new encrypted connection](#creating-new-encrypted-connection)
-* [Connecting via r2d2 connection pool](#connecting-via-r2d2-connection-pool)
-* [Retrieving supported options](#getting-supported-options)
-* [Using compression](#using-compression)
-* [Query execution](#query-execution)
-  * [USE query](https://github.com/AlexPikalov/cdrs#use-query)
-  * [CREATE query](#create-query)
-  * [Insert/Update Query (Structures serialization)](#insertupdate-query-structures-serialization)
-  * [SELECT query](#select-query)
-  * [SELECT query (mapping results)](#select-query-mapping-results)
-  * [PREPARE and EXECUTE query](#prepare-and-execute-a-query)
-* [Listen to server events](#listen-to-server-events)
-* [Cassandra clusters and load balancing](#cassandra-clusters-and-load-balancing)
-* [Performance](#performance)
-* [Supported features](#supported-features)
+```rust
+use cdrs::cluster::Cluster;
+let cluster = Cluster::new(vec!["youraddress_1:9042", "youraddress_2:9042"], authenticator);
+```
 
+First agrument is a Rust `Vec` of node addresses, the second argument could be any structure that implements `cdrs::authenticators::Authenticator` trait. This allows to use custom authentication strategies, but in this case developers should implement authenticators by themselves. Out of the box CDRS provides two types of authenticators:
 
-### Creating new connection
+* `cdrs::authenticators::NoneAuthenticator` that should be used if authentication is disabled ([Cassandra authenticator](http://cassandra.apache.org/doc/latest/configuration/cassandra_config_file.html#authenticator) is set to `AllowAllAuthenticator`) on server.
 
+* `cdrs::authenticators::PasswordAuthenticator` that should be used if authentication is enabled on the server and [authenticator](http://cassandra.apache.org/doc/latest/configuration/cassandra_config_file.html#authenticator) is `PasswordAuthenticator`:
 
 ```rust
-use cdrs::client::CDRS;
-use cdrs::authenticators::NoneAuthenticator;
-use cdrs::transport::TransportTcp;
+use cdrs::authenticators::PasswordAuthenticator;
+let authenticator = PasswordAuthenticator::new("user", "pass");
 ```
 
-After that you can create a new instance of `CDRS` and establish new connection:
+When cluster nodes are described new `Session` could be established. Each new `Session` has its own load balancing strategy as well as data compression. (CDRS supports both [Snappy](<https://en.wikipedia.org/wiki/Snappy_(compression)>) and [LZ4](<https://en.wikipedia.org/wiki/LZ4_(compression_algorithm)>) compresssions)
 
 ```rust
-let authenticator = NoneAuthenticator;
-let addr = "127.0.0.1:9042";
-let tcp_transport = TransportTcp::new(addr).unwrap();
-
-// pass authenticator and transport into CDRS' constructor
-let client = CDRS::new(tcp_transport, authenticator);
-use cdrs::compression;
-// start session without compression
-let mut session = try!(client.start(compression::None));
+let mut no_compression = cluster.connect(RoundRobin::new())
+                                  .expect("No compression connection error");
+  let mut lz4_compression = cluster.connect_lz4(RoundRobin::new())
+                                   .expect("LZ4 compression connection error");
+  let mut snappy_compression = cluster.connect_snappy(RoundRobin::new())
+                                      .expect("Snappy compression connection error");
 ```
 
+where the first argument of each connect methods is a load balancer. Each structure that implements `cdrs::load_balancing::LoadBalancingStrategy` could be used as a load balancer during establishing new `Session`. CDRS provides two strategies out of the box: `cdrs::load_balancing::{RoundRobin, Random}`. Having been set once at the start load balancing strategy cannot be changed during the session.
 
-
-### Creating new connection with authentication
-
-To use password authenticator, just include the one implemented in
-`cdrs::authenticators`.
-
-```rust
-use cdrs::client::CDRS;
-use cdrs::authenticators::PasswordAuthenticator;
-use cdrs::transport::TransportTcp;
-```
-
-After that you can create a new instance of `CDRS` and establish new connection:
+Unlike to load balancing compression method could be changed without session restart:
 
 ```rust
-let authenticator = PasswordAuthenticator::new("user", "pass");
-let addr = "127.0.0.1:9042";
-let tcp_transport = TransportTcp::new(addr).unwrap();
-
-// pass authenticator and transport into CDRS' constructor
-let client = CDRS::new(tcp_transport, authenticator);
-use cdrs::compression;
-// start session without compression
-let mut session = try!(client.start(compression::None));
+use compression::Compression;
+let mut session = cluster.connect(RoundRobin::new())
+                                  .expect("No compression connection error");
+session.compression = Compression::LZ4;
 ```
 
+### Starting new SSL-encrypted Session
 
-### Creating new encrypted connection
-
-To be able to create SSL-encrypted connection CDRS should be used with
-`ssl` feature enabled. Apart of CDRS itself _openssl_ must also be imported.
+SSL-encrypted connection is also awailable with CDRS however to get this working CDRS itself should be imported with `ssl` feature enabled:
 
 ```toml
 [dependencies]
@@ -101,471 +57,216 @@ version = "*"
 features = ["ssl"]
 ```
 
+Another difference comparing to non-encrypted connection is necessity to create [`SSLConnector`](https://docs.rs/openssl/0.10.2/openssl/ssl/struct.SslConnector.html)
+
 ```rust
+use std::path::Path;
+use openssl::ssl::{SslConnectorBuilder, SslMethod};
 use cdrs::client::CDRS;
 use cdrs::authenticators::PasswordAuthenticator;
 use cdrs::transport::TransportTls;
-use openssl::ssl::{SslConnectorBuilder, SslMethod};
-use std::path::Path;
-```
-
-After that you can create a new instance of `CDRS` and establish new connection:
-
-```rust
-let authenticator = PasswordAuthenticator::new("user", "pass");
-let addr = "127.0.0.1:9042";
 
-// here needs to be a path of your SSL certificate
+// here needs to be a path to your SSL certificate
 let path = Path::new("./node0.cer.pem");
 let mut ssl_connector_builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
 ssl_connector_builder.builder_mut().set_ca_file(path).unwrap();
 let connector = ssl_connector_builder.build();
-
-let ssl_transport = TransportTls::new(addr, &connector).unwrap();
-
-// pass authenticator and SSL transport into CDRS' constructor
-let client = CDRS::new(ssl_transport, authenticator);
 ```
 
-### Connecting via r2d2 connection pool
-
-There is an option to create [r2d2](https://github.com/sfackler/r2d2) connection pool
-of CDRS connections both plain and SSL-encrypted:
+When these preparation are done we're good to start SSL-encrypted session.
 
 ```rust
-use cdrs::connection_manager::ConnectionManager;
-
-let transport = TransportTcp::new(ADDR).unwrap();
-let authenticator = PasswordAuthenticator::new(USER, PASS);
-let manager = ConnectionManager::new(transport, authenticator, Compression::None);
-let pool = r2d2::Pool::builder()
-    .max_size(15)
-    .build(manager).unwrap();
-
-for _ in 0..20 {
-    let pool = pool.clone();
-    thread::spawn(move || {
-        let conn = pool.get().unwrap();
-        // use the connection
-        // it will be returned to the pool when it falls out of scope.
-    });
-}
-
+let mut no_compression = cluster.connect_ssl(RoundRobin::new())
+                                  .expect("No compression connection error");
+  let mut lz4_compression = cluster.connect_lz4_ssl(RoundRobin::new())
+                                   .expect("LZ4 compression connection error");
+  let mut snappy_compression = cluster.connect_snappy_ssl(RoundRobin::new())
+                                      .expect("Snappy compression connection error");
 ```
 
-There is a related example.
+More details regarding configuration Cassandra server for SSL-encrypted Client-Node communication could be found, for instance, on [DataStax website](https://docs.datastax.com/en/cassandra/3.0/cassandra/configuration/secureSSLClientToNode.html).
 
-### Getting supported options
+### Executing queries
 
-Before session established an application may want to know which options are
-supported by a server (for instance to figure out which compression to use).
-That's why `CDRS` instance has a method `get_options` which could be called
-before session get started. Options are presented as `HashMap<String, Vec<String>>`.
+CDRS `Session` implements `cdrs::query::QueryExecutor` trait that provides few options for immediate query execution:
 
 ```rust
-let options = try!(client.get_options());
-```
+// simple query
+session.query("SELECT * from my.store").unwrap();
+
+// simple query with tracing and warnings
+let with_tracing = true;
+let with_warnings = true;
+session.query_tw("SELECT * FROM my.store", with_tracing, with_warnings).unwrap();
+
+// query with query values
+let values = query_values!(1 as i32, 1 as i64);
+session.query_tw("INSERT INTO my.numbers (my_int, my_bigint) VALUES (?, ?)", values).unwrap();
+
+// query with query values, tracing and warnings
+let with_tracing = true;
+let with_warnings = true;
+let values = query_values!(1 as i32, 1 as i64);
+session.query_tw("INSERT INTO my.numbers (my_int, my_bigint) VALUES (?, ?)", values, with_tracing, with_warnings).unwrap();
+
+// query with query params
+use cdrs::query::QueryParamsBuilder;
+use cdrs::consistency::Consistency;
+
+let mut params = QueryParamsBuilder::new();
+params = params.consistency(Consistency::Any);
+session.query_with_params("SELECT * FROM my.store", params.finalize()).unwrap();
 
-**This should be called before session started** to let you know which compression
-to choose and because session object borrows `CDRS` instance.
+// query with query params and tracing, warnings
+use cdrs::query::QueryParamsBuilder;
+use cdrs::consistency::Consistency;
 
-### Using compression
+let with_tracing = true;
+let with_warnings = true;
 
-Two types of compression are supported - [snappy](https://code.google.com/p/snappy/)
-and [lz4](https://code.google.com/p/lz4/). To use compression just start connection
-with desired type:
+let mut params = QueryParamsBuilder::new();
+params = params.consistency(Consistency::Any);
 
-```rust
-use cdrs::compression::Compression;
-// session without compression
-let mut session_res = client.start(Compression::None);
-// session  lz4 compression
-let mut session_res = client.start(Compression::Lz4);
-// v with snappy compression
-let mut session_res = client.start(Compression::Snappy);
+session.query_with_params_tw("SELECT * FROM my.store", params.finalize(), with_tracing, with_warnings).unwrap();
 ```
 
-### Query execution
+### Preparing queries
 
-Query execution is provided in scope of Session. So to start executing queries
-you need to start Session first.
+During preparing a query a server parses the query, saves parsing result into cache and returns back to a client an ID that could be further used for executing prepared statement with different parameters (such as values, consistency etc.). When a server executes prepared query it doesn't need to parse it so parsing step will be skipped.
 
-#### Use Query:
+CDRS `Session` implements `cdrs::query::PrepareExecutor` trait that provides few option for preparing query:
 
 ```rust
+let prepared_query = session.prepare("INSERT INTO my.store (my_int, my_bigint) VALUES (?, ?)").unwrap();
 
-let create_query: Query = QueryBuilder::new("USE my_namespace;").finalize();
-let with_tracing = false;
-let with_warnings = false;
+// or with tracing and warnings
+let with_tracing = true;
+let with_warnings = true;
 
-match session.query(create_query, with_tracing, with_warnings) {
-    Ok(set_keyspace) => {
-        // use_keyspace is a result frame of type SetKeyspace
-    },
-    Err(err) => log!(err)
-}
+let prepred_query = session.prepare_tw("INSERT INTO my.store (my_int, my_bigint) VALUES (?, ?)", with_tracing, with_warnings).unwrap();
 ```
 
-#### Create Query:
+### Executing prepared queries
 
-Creating new table could be performed via `session.query`. In case of success
-method returns Schema Change frame that contains Change Type, Target and options
-that contain namespace and a name of newly created table.
+When query is prepared on the server client gets prepared query id of type `cdrs::query::PreparedQuery`. Having such id it's possible to execute prepared query using session methods from `cdrs::query::ExecExecutor`:
 
 ```rust
-use std::default::Default;
-use cdrs::query::{Query, QueryBuilder};
-use cdrs::consistency::Consistency;
-
-let mut create_query: Query = QueryBuilder::new("CREATE TABLE keyspace.emp (
-    empID int,
-    deptID int,
-    first_name varchar,
-    last_name varchar,
-    PRIMARY KEY (empID, deptID)
-    );")
-    .consistency(Consistency::One)
-    .finalize();
-let with_tracing = false;
-let with_warnings = false;
+// execute prepared query without specifying any extra parameters or values
+session.exec(&preparedQuery).unwrap();
 
-let table_created = session.query(create_query, with_tracing, with_warnings).is_ok();
-
-```
+// execute prepared query with tracing and warning information
+let with_tracing = true;
+let with_warnings = true;
 
-#### Insert/Update Query (Structures serialization)
+session.exec_tw(&preparedQuery, with_tracing, with_warnings).unwrap();
 
-In order to perform insertion/updating of a Rust structure you'd need
-to perform its serialization first. CDRS provides `Into<Value>` implementation
-(and since CDRS version 1.2.0 derivable `IntoCDRSValue`) trait.
+// execute prepared query with values
+let values_with_names = query_values!{"my_bigint" => bigint, "my_int" => int};
 
-After that it's possible to create a query with values:
-
-```rust
-let ints = IntsV3 {
-      bigint: 123,
-      int: 234,
-  };
-let values: Vec<Value> = vec![ints.bigint.into(), ints.int.into()];
-
-let insert_query = QueryBuilder::new(INSERT_QUERY_STRING)
-    .values(values)
-    .finalize();
-```
-
-Conversion of nested structures could be performed if we'd consider inner
-structures as Cassandra User Defined Type:
-
-```rust
-#[derive(IntoCDRSValues)]
-struct SomeUdt {
-  value: i32
-}
-
-struct RowObj {
-  id: i64,
-  udt: SomeUdt
-}
+session.exec_with_values(&preparedQuery, values_with_names).unwrap();
 
-let obj = {
-  id: 1,
-  udt: SomeUdt { value: 128 }
-};
+// execute prepared query with values with warnings and tracing information
+let with_tracing = true;
+let with_warnings = true;
 
-let values: Vec<Value> = vec![obj.id.into_cdrs_value(), obj.udt.into_cdrs_value()];
+let values_with_names = query_values!{"my_bigint" => 1 as i64, "my_int" => 2 as i32};
 
-let insert_query = QueryBuilder::new(INSERT_QUERY_STRING)
-    .values(values)
-    .finalize();
-```
+session.exec_with_values_tw(&preparedQuery, values_with_names, with_tracing, with_warnings).unwrap();
 
-#### Select Query:
+// execute prepared query with parameters
+use cdrs::query::QueryParamsBuilder;
+use cdrs::consistency::Consistency;
 
-As a response to select query CDRS returns a result frame of type Rows with
-data items (columns) encoded in Cassandra's way.
+let mut params = QueryParamsBuilder::new();
+params = params.consistency(Consistency::Any);
+session.exec_with_parameters(&preparedQuery, params.finalize()).unwrap();
 
-```rust
-use std::default::Default;
-use cdrs::client::Query;
+// execute prepared query with parameters, tracing and warning information
+use cdrs::query::QueryParamsBuilder;
 use cdrs::consistency::Consistency;
 
-let select_query: Query = QueryBuilder::new("SELECT * FROM keyspace.table;").finalize();
-let with_tracing = false;
-let with_warnings = false;
-
-match session.query(select_query, with_tracing, with_warnings) {
-    Ok(res) => println!("Result frame: {:?},\nparsed body: {:?}", res, res.get_body());,
-    Err(err) => log!(err)
-}
+let with_tracing = true;
+let with_warnings = true;
+let mut params = QueryParamsBuilder::new();
+params = params.consistency(Consistency::Any);
+session.exec_with_parameters_tw(&preparedQuery, params.finalize(), with_tracing, with_warnings).unwrap();
 ```
 
-#### Select Query (mapping results):
-
-Once CDRS got response to `SELECT` query you can map rows encapsulated within
-`Result` frame into Rust values or into `List`, `Map` or `UDT` helper structures
-which provide a way to convert wrapped values into plain ones.
+### Batch queries
 
-As an example let's consider a case when application gets a collection
-of messages of following format:
+CDRS `Session` supports batching few queries in a single request to Apache Cassandra via implementing `cdrs::query::BatchExecutor` trait:
 
 ```rust
-
-struct Message {
-    pub author: String,
-    pub text: String,
-    pub optional_field: Option<String>
-}
-
+// batch two queries
+use cdrs::query::{BatchQueryBuilder, QueryBatch};
+
+let mut queries = BatchQueryBuilder::new();
+queries = queries.add_query_prepared(&prepared_query);
+queries = queries.add_query("INSERT INTO my.store (my_int) VALUES (?)", query_values!(1 as i32));
+session.batch_with_params(queries.finalyze());
+
+// batch queries with tracing and warning information
+use cdrs::query::{BatchQueryBuilder, QueryBatch};
+
+let with_tracing = true;
+let with_warnings = true;
+let mut queries = BatchQueryBuilder::new();
+queries = queries.add_query_prepared(&prepared_query);
+queries = queries.add_query("INSERT INTO my.store (my_int) VALUES (?)", query_values!(1 as i32));
+session.batch_with_params_tw(queries.finalyze(), with_tracing, with_warnings);
 ```
 
-To get a collection of messages `Vec<Message>` let's convert a result of query
-into collection of rows `Vec<cdrs::types::row::Row>` and then convert each column
-into appropriate Rust type:
+### Query values types
 
-```rust
-use cdrs::error::{Result as CResult};
-
-let res_body = parsed.get_body().unwrap();
-let rows = res_body.into_rows().unwrap();
-let messages: Vec<CResult<Message>> = rows
-    .iter()
-    .map(|row| Message {
-        author: row.r_by_name("author").unwrap(),
-        text: row.r_by_name("text").unwrap(),
-        optional_field: row.get_by_name("optional_field")
-    })
-    .collect();
+Accordingly to specification along with queries there could be provided something that is called values. Apache Cassandra server will use values instead of `?` symbols from a query string.
 
-```
+There are two types of queries defined in the spec and supported by CDRS driver. Each of these two types could be easily constructed via provided `query_values!` macros.
 
-or by column position:
+* simple values - could be imagine as a list of values. The order of simple values matters because server will put them in the same number as columns were provided in query string.
 
 ```rust
-let messages: Vec<CResult<Message>> = rows
-    .iter()
-    .map(|row| Message {
-        author: row.r_by_index(0).unwrap(),
-        text: row.r_by_index(1).unwrap(),
-        optional_field: row.get_by_index(2)
-    })
-    .collect();
+let simple_values = query_values!(1 as i32, 2 as i32);
 ```
 
-There is no difference between Cassandra's List and Sets in terms of Rust.
-They could be represented as `Vec<T>`. To convert a frame into a structure
-that contains a collection of elements do as follows:
+* named values are similar to hash maps, where keys represent column names which the a value has to be assigned to.
 
 ```rust
-
-struct Author {
-    pub name: String,
-    pub messages: Vec<String>
-}
-
-//...
-use cdrs::error::{Result as CResult};
-let res_body = parsed.get_body().unwrap();
-let rows = res_body.into_rows().unwrap();
-let messages: Vec<CAuthor> = rows
-    .iter()
-    .map(|row| {
-        let name: String = row.r_by_name("name").unwrap();
-        let messages: Vec<String> = row
-            // unwrap Option<CResult<T>>, where T implements AsRust
-            .r_by_name("messages").unwrap()
-            .as_r_rust().unwrap();
-        return Author {
-            author: name,
-            text: messages
-        };
-    })
-    .collect();
-
+let values_with_names = query_values!{"my_bigint" => 1 as i64, "my_int" => 2 as i32};
 ```
 
-#### Prepare and execute a query:
-
-Prepare-execute query is also supported:
+Each type that implements `Into<cdrs::types::value::Value>` could be used as a value in `query_values!` macros. For primitive types please refer to following [wrapper CDRS types](https://github.com/AlexPikalov/cdrs/blob/master/type-mapping.md) that could be easily converted to `Value`. For custom types (in Cassandra terminology User Defined Types) `IntoCDRSValue` derive could be used:
 
 ```rust
-  // NOTE: keyspace "keyspace" should already exist
-  let create_table_cql = "USE keyspace;".to_string();
-  let with_tracing = false;
-  let with_warnings = false;
-
-  // prepare a query
-  let prepared = session.prepare(create_table_cql, with_tracing, with_warnings)
-    .unwrap()
-    .get_body()
-    .into_prepared()
-    .unwrap();
-
-  // execute prepared query
-  let execution_params = QueryParamsBuilder::new(Consistency::One).finalize();
-  let query_id = prepared.id;
-  let executed = session.execute(query_id, execution_params, false, false)
-    .unwrap()
-    .get_body()
-    .unwrap()
-    .into_set_keyspace()
-    .unwrap();
-```
-
-It's also makes sense to use prepare query in pair with [batching](https://github.com/AlexPikalov/cdrs/blob/master/examples/batch_queries.rs) few queries.
-
-### Listen to Server events
-
-CDRS provides functionality which allows listening to server events. Events
-inform user about following changes:
-
-* **Topology change** - events related to change in the cluster topology.
-Currently, events are sent when new nodes are added to the cluster, and
-when nodes are removed.
-
-* **Status change** - events related to change of node status. Currently,
-up/down events are sent.
-
-* **Schema_change** - events related to schema change.
-
-Current implementation allows to move listener and stream handler into separate
-threads so then (as we believe) developers could leverage whatever
-async IO library they want.
-
-To find an examples please refer to [examples](./examples/server_events.rs).
-
-### Cassandra clusters and load balancing
-
-CDRS supports Apache Cassandra clusters and load balancing. In order to connect
-to desired nodes you have to provide related transports (either TCP or TLS)
-and to configure r2d2 pool.
+#[derive(Debug, IntoCDRSValue)]
+struct Udt {
+    pub number: i32,
+    pub number_16: i16,
+    pub number_8: N,
+}
 
-```rust
-let cluster = vec![_ADDR1, _ADDR2]
-    .iter()
-    .map(|addr| TransportTcp::new(addr).unwrap())
-    .collect();
-let pool = r2d2::Pool::builder()
-    .max_size(15)
-    .build(manager).expect("Failed to initialize Cassandra connection pool");
-```
-After that you need to choose desired load balancing strategy and instantiate
-cluster collection manager. At current moment
-two static strategies were implemented: `Random` and `RoundRobin`.
-```rust
-let load_balancer = LoadBalancer::new(cluster, LoadBalancingStrategy::RoundRobin);
-let manager = ClusterConnectionManager::new(load_balancer, authenticator, Compression::None);
+// for nested structures it works as well
+#[derive(Debug, IntoCDRSValue)]
+struct N {
+    pub n: i16,
+}
 ```
-After that you'll be able to communicate with cluster via r2d2 connection pool.
-
-### Performance
-
-Folder `./benches` contains benchmark tests. This is an attempt to measure the
-driver performance and to compare it with already existing solutions. Also
-periodically running benchmark tests might help to identify slow parts of CDRS
-and prevent performance degradation caused by changes.
-
-To get current result you need either to have nightly Rust installed on your
-machine or install [rustup](https://www.rustup.rs/).
-
-In case you have nightly Rust, just run `cargo bench`. If you have rustup --
-`rustup run nightly cargo bench`.
-
-To find last results refer to [benchmarks.md](./benchmarks.md)
-
-### Supported features
-
-- [x] lz4 decompression
-- [x] snappy decompression
-- [x] password authorization
-- [x] tracing information
-- [x] warning information
-- [x] SSL encrypted connection
-- [x] load balancing
-- [x] connection pooling
-
-### Frames
-
-#### Request
-
-- [x] STARTUP
-- [x] AUTH_RESPONSE
-- [x] OPTIONS
-- [x] QUERY
-- [x] PREPARE
-- [x] EXECUTE
-- [x] BATCH
-- [x] REGISTER
-
-#### Response
-
-- [x] ERROR
-- [x] READY
-- [x] AUTHENTICATE
-- [x] SUPPORTED
-- [x] RESULT (Void)
-- [x] RESULT (Rows)
-- [x] RESULT (Set_keyspace)
-- [x] RESULT (Prepared)
-- [x] RESULT (Schema_change)
-  - [x] Target KEYSPACE
-  - [x] Target TABLE
-  - [x] Target TYPE
-  - [x] Target FUNCTION
-  - [x] Target AGGREGATE
-- [x] EVENT
-- [x] AUTH_CHALLENGE
-- [x] AUTH_SUCCESS
-
-
-Issues
-------
-
-Feel free to submit issues and enhancement requests.
-
-Contributing
-------------
-
-Please refer to each project's style guidelines and guidelines for submitting patches and additions. In general, we follow the "fork-and-pull" Git workflow.
-
- 1. **Fork** the repo on GitHub
- 2. **Clone** the project to your own machine
- 3. **Commit** changes to your own branch
- 4. **Run  ```cargo test --all-features && cargo fmt -- --write-mode=diff```
- 5. **Push** your work back up to your fork
- 6. Submit a **Pull request** so that we can review your changes
-
-NOTE: Be sure to merge the latest from "upstream" before making a pull request!
-while running the tests you might need a local cassandra server working.
-The easiest way was to run cassandra on docker on local machine
-
 
-Running Cassandra on Local
----------------------------
+Look into this [link](https://github.com/AlexPikalov/into-cdrs-value-derive/tree/master/example) to find a full example how to use CDRS + [_into-cdrs-value-derive_](https://github.com/AlexPikalov/into-cdrs-value-derive) crate.
 
- 1. If you have docker on the machine type the below command
-     ```
-     docker run --name cassandra-1 -d -p 9042:9042 -p 9160:9160 cassandra:2.2.1
+### Mapping results into Rust structures
 
-     ```
-     `docker ps `
-       should show an output like below
+In ordert to query information from Cassandra DB and transform results to Rust types an structures each row in a query result should be transformed leveraging one of following traits provided by CDRS `cdrs::types::{AsRustType, AsRust, IntoRustByName, ByName, IntoRustByIndex, ByIndex}`.
 
-     ```
-        CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                                     NAMES
-        a78c3a43bf1b        cassandra:2.2.1     "/docker-entrypoin..."   4 days ago          Up 4 days           7000-7001/tcp, 0.0.0.0:9042->9042/tcp, 7199/tcp, 0.0.0.0:9160->9160/tcp   cassandra-1
-      ```
+* `AsRustType` may be used in order to transform such complex structures as Cassandra lists, sets, tuples. The Cassandra value in this case could non-set and null values.
 
- 2. If docker is new to your tool set; it is never too late to know this awesome tool https://docs.docker.com/docker-for-mac/
+* `AsRust` trait may be used for similar purposes as `AsRustType` but it assumes that Cassandra value is neither non-set nor null value. Otherwise it panics.
 
- Running Cassandra Cluster on local
- -----------------------------------
+* `IntoRustByName` trait may be used to access a value as a Rust structure/type by name. Such as in case of rows where each column has its own name, and maps. These values may be as well non-set and null.
 
-To start Apache Cassandra cluster on local just run `tests/build-cluster.sh`.
-This script will create two nodes of Apache Cassandra 3.9 with following exposed
-ports: 9042 and 9043.
+* `ByName` trait is the same as `IntoRustByName` but value should be neither non-set nor null. Otherwise it panics.
 
-### License
+* `IntoRustByIndex` is the same as `IntoRustByName` but values could be accessed via column index basing on their order provided in query. These values may be as well non-set and null.
 
-* [MIT License](https://github.com/AlexPikalov/cdrs/blob/master/LICENSE-MIT)
+* `ByIndex` is the same as `IntoRustByIndex` but value can be neither non-set nor null. Otherwise it panics.
 
-* [Apache-2.0](https://github.com/AlexPikalov/cdrs/blob/master/LICENSE-APACHE)
+Relations between Cassandra and Rust types are described in [type-mapping.md](https://github.com/AlexPikalov/cdrs/blob/master/type-mapping.md). For details see examples.
diff --git a/README_1.md b/README_1.md
new file mode 100644
index 0000000..f453893
--- /dev/null
+++ b/README_1.md
@@ -0,0 +1,554 @@
+# CDRS [![crates.io version](https://img.shields.io/crates/v/cdrs.svg)](https://crates.io/crates/cdrs) [![Build Status](https://travis-ci.org/AlexPikalov/cdrs.svg?branch=master)](https://travis-ci.org/AlexPikalov/cdrs) [![Build status](https://ci.appveyor.com/api/projects/status/sirj4flws6o0dvb7/branch/master?svg=true)](https://ci.appveyor.com/project/harrydevnull/cdrs/branch/master)
+
+**CDRS** is a native driver for [Apache Cassandra](http://cassandra.apache.org) written in [Rust](https://www.rust-lang.org).
+The motivation to write it in Rust is a lack of native one.
+Existing ones are bindings to C clients.
+
+[Documentation](https://docs.rs/cdrs)
+
+**CDRS** completely implements 4-th version of [Cassandra protocol](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec).
+Also it provides tools for [mapping results](#select-query-mapping-results)
+into Rust structures.
+
+## Content
+
+* [Creating new connection and authorization](#creating-new-connection-and-authorization)
+* [Creating new encrypted connection](#creating-new-encrypted-connection)
+* [Connecting via r2d2 connection pool](#connecting-via-r2d2-connection-pool)
+* [Retrieving supported options](#getting-supported-options)
+* [Using compression](#using-compression)
+* [Query execution](#query-execution)
+  * [USE query](https://github.com/AlexPikalov/cdrs#use-query)
+  * [CREATE query](#create-query)
+  * [Insert/Update Query (Structures serialization)](#insertupdate-query-structures-serialization)
+  * [SELECT query](#select-query)
+  * [SELECT query (mapping results)](#select-query-mapping-results)
+  * [PREPARE and EXECUTE query](#prepare-and-execute-a-query)
+* [Listen to server events](#listen-to-server-events)
+* [Cassandra clusters and load balancing](#cassandra-clusters-and-load-balancing)
+* [Performance](#performance)
+* [Supported features](#supported-features)
+
+### Creating new connection
+
+```rust
+use cdrs::client::CDRS;
+use cdrs::authenticators::NoneAuthenticator;
+use cdrs::transport::TransportTcp;
+```
+
+After that you can create a new instance of `CDRS` and establish new connection:
+
+```rust
+let authenticator = NoneAuthenticator;
+let addr = "127.0.0.1:9042";
+let tcp_transport = TransportTcp::new(addr).unwrap();
+
+// pass authenticator and transport into CDRS' constructor
+let client = CDRS::new(tcp_transport, authenticator);
+use cdrs::compression;
+// start session without compression
+let mut session = try!(client.start(compression::None));
+```
+
+### Creating new connection with authentication
+
+To use password authenticator, just include the one implemented in
+`cdrs::authenticators`.
+
+```rust
+use cdrs::client::CDRS;
+use cdrs::authenticators::PasswordAuthenticator;
+use cdrs::transport::TransportTcp;
+```
+
+After that you can create a new instance of `CDRS` and establish new connection:
+
+```rust
+let authenticator = PasswordAuthenticator::new("user", "pass");
+let addr = "127.0.0.1:9042";
+let tcp_transport = TransportTcp::new(addr).unwrap();
+
+// pass authenticator and transport into CDRS' constructor
+let client = CDRS::new(tcp_transport, authenticator);
+use cdrs::compression;
+// start session without compression
+let mut session = try!(client.start(compression::None));
+```
+
+### Creating new encrypted connection
+
+To be able to create SSL-encrypted connection CDRS should be used with
+`ssl` feature enabled. Apart of CDRS itself _openssl_ must also be imported.
+
+```toml
+[dependencies]
+openssl = "0.9.6"
+
+[dependencies.cdrs]
+version = "*"
+features = ["ssl"]
+```
+
+```rust
+use cdrs::client::CDRS;
+use cdrs::authenticators::PasswordAuthenticator;
+use cdrs::transport::TransportTls;
+use openssl::ssl::{SslConnectorBuilder, SslMethod};
+use std::path::Path;
+```
+
+After that you can create a new instance of `CDRS` and establish new connection:
+
+```rust
+let authenticator = PasswordAuthenticator::new("user", "pass");
+let addr = "127.0.0.1:9042";
+
+// here needs to be a path of your SSL certificate
+let path = Path::new("./node0.cer.pem");
+let mut ssl_connector_builder = SslConnectorBuilder::new(SslMethod::tls()).unwrap();
+ssl_connector_builder.builder_mut().set_ca_file(path).unwrap();
+let connector = ssl_connector_builder.build();
+
+let ssl_transport = TransportTls::new(addr, &connector).unwrap();
+
+// pass authenticator and SSL transport into CDRS' constructor
+let client = CDRS::new(ssl_transport, authenticator);
+```
+
+### Connecting via r2d2 connection pool
+
+There is an option to create [r2d2](https://github.com/sfackler/r2d2) connection pool
+of CDRS connections both plain and SSL-encrypted:
+
+```rust
+use cdrs::connection_manager::ConnectionManager;
+
+let config = r2d2::Config::builder()
+    .pool_size(15)
+    .build();
+let transport = TransportTcp::new(ADDR).unwrap();
+let authenticator = PasswordAuthenticator::new(USER, PASS);
+let manager = ConnectionManager::new(transport, authenticator, Compression::None);
+
+let pool = r2d2::Pool::new(config, manager).unwrap();
+
+for _ in 0..20 {
+    let pool = pool.clone();
+    thread::spawn(move || {
+        let conn = pool.get().unwrap();
+        // use the connection
+        // it will be returned to the pool when it falls out of scope.
+    });
+}
+```
+
+There is a related example.
+
+### Getting supported options
+
+Before session established an application may want to know which options are
+supported by a server (for instance to figure out which compression to use).
+That's why `CDRS` instance has a method `get_options` which could be called
+before session get started. Options are presented as `HashMap<String, Vec<String>>`.
+
+```rust
+let options = try!(client.get_options());
+```
+
+**This should be called before session started** to let you know which compression
+to choose and because session object borrows `CDRS` instance.
+
+### Using compression
+
+Two types of compression are supported - [snappy](https://code.google.com/p/snappy/)
+and [lz4](https://code.google.com/p/lz4/). To use compression just start connection
+with desired type:
+
+```rust
+use cdrs::compression::Compression;
+// session without compression
+let mut session_res = client.start(Compression::None);
+// session  lz4 compression
+let mut session_res = client.start(Compression::Lz4);
+// v with snappy compression
+let mut session_res = client.start(Compression::Snappy);
+```
+
+### Query execution
+
+Query execution is provided in scope of Session. So to start executing queries
+you need to start Session first.
+
+#### Use Query:
+
+```rust
+let create_query: Query = QueryBuilder::new("USE my_namespace;").finalize();
+let with_tracing = false;
+let with_warnings = false;
+
+match session.query(create_query, with_tracing, with_warnings) {
+    Ok(set_keyspace) => {
+        // use_keyspace is a result frame of type SetKeyspace
+    },
+    Err(err) => log!(err)
+}
+```
+
+#### Create Query:
+
+Creating new table could be performed via `session.query`. In case of success
+method returns Schema Change frame that contains Change Type, Target and options
+that contain namespace and a name of newly created table.
+
+```rust
+use std::default::Default;
+use cdrs::query::{Query, QueryBuilder};
+use cdrs::consistency::Consistency;
+
+let mut create_query: Query = QueryBuilder::new("CREATE TABLE keyspace.emp (
+    empID int,
+    deptID int,
+    first_name varchar,
+    last_name varchar,
+    PRIMARY KEY (empID, deptID)
+    );")
+    .consistency(Consistency::One)
+    .finalize();
+let with_tracing = false;
+let with_warnings = false;
+
+let table_created = session.query(create_query, with_tracing, with_warnings).is_ok();
+```
+
+#### Insert/Update Query (Structures serialization)
+
+In order to perform insertion/updating of a Rust structure you'd need
+to perform its serialization first. CDRS provides `Into<Value>` implementation
+(and since CDRS version 1.2.0 derivable `IntoCDRSValue`) trait.
+
+After that it's possible to create a query with values:
+
+```rust
+let ints = IntsV3 {
+      bigint: 123,
+      int: 234,
+  };
+let values: Vec<Value> = vec![ints.bigint.into(), ints.int.into()];
+
+let insert_query = QueryBuilder::new(INSERT_QUERY_STRING)
+    .values(values)
+    .finalize();
+```
+
+Conversion of nested structures could be performed if we'd consider inner
+structures as Cassandra User Defined Type:
+
+```rust
+#[derive(IntoCDRSValues)]
+struct SomeUdt {
+  value: i32
+}
+
+struct RowObj {
+  id: i64,
+  udt: SomeUdt
+}
+
+let obj = {
+  id: 1,
+  udt: SomeUdt { value: 128 }
+};
+
+let values: Vec<Value> = vec![obj.id.into_cdrs_value(), obj.udt.into_cdrs_value()];
+
+let insert_query = QueryBuilder::new(INSERT_QUERY_STRING)
+    .values(values)
+    .finalize();
+```
+
+#### Select Query:
+
+As a response to select query CDRS returns a result frame of type Rows with
+data items (columns) encoded in Cassandra's way.
+
+```rust
+use std::default::Default;
+use cdrs::client::Query;
+use cdrs::consistency::Consistency;
+
+let select_query: Query = QueryBuilder::new("SELECT * FROM keyspace.table;").finalize();
+let with_tracing = false;
+let with_warnings = false;
+
+match session.query(select_query, with_tracing, with_warnings) {
+    Ok(res) => println!("Result frame: {:?},\nparsed body: {:?}", res, res.get_body());,
+    Err(err) => log!(err)
+}
+```
+
+#### Select Query (mapping results):
+
+Once CDRS got response to `SELECT` query you can map rows encapsulated within
+`Result` frame into Rust values or into `List`, `Map` or `UDT` helper structures
+which provide a way to convert wrapped values into plain ones.
+
+As an example let's consider a case when application gets a collection
+of messages of following format:
+
+```rust
+struct Message {
+    pub author: String,
+    pub text: String,
+    pub optional_field: Option<String>
+}
+```
+
+To get a collection of messages `Vec<Message>` let's convert a result of query
+into collection of rows `Vec<cdrs::types::row::Row>` and then convert each column
+into appropriate Rust type:
+
+```rust
+use cdrs::error::{Result as CResult};
+
+let res_body = parsed.get_body().unwrap();
+let rows = res_body.into_rows().unwrap();
+let messages: Vec<CResult<Message>> = rows
+    .iter()
+    .map(|row| Message {
+        author: row.r_by_name("author").unwrap(),
+        text: row.r_by_name("text").unwrap(),
+        optional_field: row.get_by_name("optional_field")
+    })
+    .collect();
+```
+
+or by column position:
+
+```rust
+let messages: Vec<CResult<Message>> = rows
+    .iter()
+    .map(|row| Message {
+        author: row.r_by_index(0).unwrap(),
+        text: row.r_by_index(1).unwrap(),
+        optional_field: row.get_by_index(2)
+    })
+    .collect();
+```
+
+There is no difference between Cassandra's List and Sets in terms of Rust.
+They could be represented as `Vec<T>`. To convert a frame into a structure
+that contains a collection of elements do as follows:
+
+```rust
+struct Author {
+    pub name: String,
+    pub messages: Vec<String>
+}
+
+//...
+use cdrs::error::{Result as CResult};
+let res_body = parsed.get_body().unwrap();
+let rows = res_body.into_rows().unwrap();
+let messages: Vec<CAuthor> = rows
+    .iter()
+    .map(|row| {
+        let name: String = row.r_by_name("name").unwrap();
+        let messages: Vec<String> = row
+            // unwrap Option<CResult<T>>, where T implements AsRust
+            .r_by_name("messages").unwrap()
+            .as_r_rust().unwrap();
+        return Author {
+            author: name,
+            text: messages
+        };
+    })
+    .collect();
+```
+
+#### Prepare and execute a query:
+
+Prepare-execute query is also supported:
+
+```rust
+  // NOTE: keyspace "keyspace" should already exist
+  let create_table_cql = "USE keyspace;".to_string();
+  let with_tracing = false;
+  let with_warnings = false;
+
+  // prepare a query
+  let prepared = session.prepare(create_table_cql, with_tracing, with_warnings)
+    .unwrap()
+    .get_body()
+    .into_prepared()
+    .unwrap();
+
+  // execute prepared query
+  let execution_params = QueryParamsBuilder::new(Consistency::One).finalize();
+  let query_id = prepared.id;
+  let executed = session.execute(query_id, execution_params, false, false)
+    .unwrap()
+    .get_body()
+    .unwrap()
+    .into_set_keyspace()
+    .unwrap();
+```
+
+It's also makes sense to use prepare query in pair with [batching](https://github.com/AlexPikalov/cdrs/blob/master/examples/batch_queries.rs) few queries.
+
+### Listen to Server events
+
+CDRS provides functionality which allows listening to server events. Events
+inform user about following changes:
+
+* **Topology change** - events related to change in the cluster topology.
+  Currently, events are sent when new nodes are added to the cluster, and
+  when nodes are removed.
+
+* **Status change** - events related to change of node status. Currently,
+  up/down events are sent.
+
+* **Schema_change** - events related to schema change.
+
+Current implementation allows to move listener and stream handler into separate
+threads so then (as we believe) developers could leverage whatever
+async IO library they want.
+
+To find an examples please refer to [examples](./examples/server_events.rs).
+
+### Cassandra clusters and load balancing
+
+CDRS supports Apache Cassandra clusters and load balancing. In order to connect
+to desired nodes you have to provide related transports (either TCP or TLS)
+and to configure r2d2 pool.
+
+```rust
+let cluster = vec![_ADDR1, _ADDR2]
+    .iter()
+    .map(|addr| TransportTcp::new(addr).unwrap())
+    .collect();
+let config = r2d2::Config::builder()
+    .pool_size(15)
+    .build();
+```
+
+After that you need to choose desired load balancing strategy and instantiate
+cluster collection manager. At current moment
+two static strategies were implemented: `Random` and `RoundRobin`.
+
+```rust
+let load_balancer = LoadBalancer::new(cluster, LoadBalancingStrategy::RoundRobin);
+let manager = ClusterConnectionManager::new(load_balancer, authenticator, Compression::None);
+```
+
+After that you'll be able to communicate with cluster via r2d2 connection pool.
+
+### Performance
+
+Folder `./benches` contains benchmark tests. This is an attempt to measure the
+driver performance and to compare it with already existing solutions. Also
+periodically running benchmark tests might help to identify slow parts of CDRS
+and prevent performance degradation caused by changes.
+
+To get current result you need either to have nightly Rust installed on your
+machine or install [rustup](https://www.rustup.rs/).
+
+In case you have nightly Rust, just run `cargo bench`. If you have rustup --
+`rustup run nightly cargo bench`.
+
+To find last results refer to [benchmarks.md](./benchmarks.md)
+
+### Supported features
+
+* [x] lz4 decompression
+* [x] snappy decompression
+* [x] password authorization
+* [x] tracing information
+* [x] warning information
+* [x] SSL encrypted connection
+* [x] load balancing
+* [x] connection pooling
+
+### Frames
+
+#### Request
+
+* [x] STARTUP
+* [x] AUTH_RESPONSE
+* [x] OPTIONS
+* [x] QUERY
+* [x] PREPARE
+* [x] EXECUTE
+* [x] BATCH
+* [x] REGISTER
+
+#### Response
+
+* [x] ERROR
+* [x] READY
+* [x] AUTHENTICATE
+* [x] SUPPORTED
+* [x] RESULT (Void)
+* [x] RESULT (Rows)
+* [x] RESULT (Set_keyspace)
+* [x] RESULT (Prepared)
+* [x] RESULT (Schema_change)
+  * [x] Target KEYSPACE
+  * [x] Target TABLE
+  * [x] Target TYPE
+  * [x] Target FUNCTION
+  * [x] Target AGGREGATE
+* [x] EVENT
+* [x] AUTH_CHALLENGE
+* [x] AUTH_SUCCESS
+
+## Issues
+
+Feel free to submit issues and enhancement requests.
+
+## Contributing
+
+Please refer to each project's style guidelines and guidelines for submitting patches and additions. In general, we follow the "fork-and-pull" Git workflow.
+
+1. **Fork** the repo on GitHub
+2. **Clone** the project to your own machine
+3. **Commit** changes to your own branch
+4. \*\*Run `cargo test --all-features && cargo fmt -- --write-mode=diff`
+5. **Push** your work back up to your fork
+6. Submit a **Pull request** so that we can review your changes
+
+NOTE: Be sure to merge the latest from "upstream" before making a pull request!
+while running the tests you might need a local cassandra server working.
+The easiest way was to run cassandra on docker on local machine
+
+## Running Cassandra on Local
+
+1. If you have docker on the machine type the below command
+
+   ```
+   docker run --name cassandra-1 -d -p 9042:9042 -p 9160:9160 cassandra:2.2.1
+   ```
+
+   `docker ps`
+   should show an output like below
+
+   ```
+      CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                                     NAMES
+      a78c3a43bf1b        cassandra:2.2.1     "/docker-entrypoin..."   4 days ago          Up 4 days           7000-7001/tcp, 0.0.0.0:9042->9042/tcp, 7199/tcp, 0.0.0.0:9160->9160/tcp   cassandra-1
+   ```
+
+2. If docker is new to your tool set; it is never too late to know this awesome tool https://docs.docker.com/docker-for-mac/
+
+Running Cassandra Cluster on local
+
+---
+
+To start Apache Cassandra cluster on local just run `tests/build-cluster.sh`.
+This script will create two nodes of Apache Cassandra 3.9 with following exposed
+ports: 9042 and 9043.
+
+### License
+
+* [MIT License](https://github.com/AlexPikalov/cdrs/blob/master/LICENSE-MIT)
+
+* [Apache-2.0](https://github.com/AlexPikalov/cdrs/blob/master/LICENSE-APACHE)
diff --git a/appveyor.yml b/appveyor.yml
index 8152d62..7bace82 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -121,4 +121,4 @@ build: false
 #directly or perform other testing commands. Rust will automatically be placed in the PATH
 # environment variable.
 test_script:
-  - cargo test --features appveyor --verbose %cargoflags%
\ No newline at end of file
+  - cargo test --verbose %cargoflags%
\ No newline at end of file
diff --git a/benches/collection_types.rs b/benches/collection_types.rs
deleted file mode 100644
index 7cd3ab2..0000000
--- a/benches/collection_types.rs
+++ /dev/null
@@ -1,428 +0,0 @@
-#![feature(test)]
-extern crate test;
-
-extern crate cdrs;
-extern crate uuid;
-extern crate time;
-extern crate regex;
-#[macro_use]
-extern crate maplit;
-
-use test::Bencher;
-
-mod common;
-use common::*;
-
-use uuid::Uuid;
-use cdrs::query::QueryBuilder;
-use cdrs::types::{IntoRustByName, AsRust};
-use cdrs::types::value::Value;
-use cdrs::types::list::List;
-use cdrs::types::map::Map;
-
-use std::str::FromStr;
-use std::collections::HashMap;
-
-#[bench]
-#[cfg(not(feature = "appveyor"))]
-fn list_body_parse(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_lists \
-               (my_text_list frozen<list<text>> PRIMARY KEY, \
-               my_nested_list list<frozen<list<int>>>)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_text_list = vec!["text1".to_string(),
-                            "text2".to_string(),
-                            "text3".to_string()];
-    let my_nested_list: Vec<Vec<i32>> =
-        vec![vec![1, 2, 3], vec![999, 888, 777, 666, 555], vec![-1, -2]];
-    let values: Vec<Value> = vec![my_text_list.clone().into(), my_nested_list.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_lists \
-               (my_text_list, my_nested_list) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_lists";
-    let query = QueryBuilder::new(cql).finalize();
-    let res = session.query(query, false, false).expect("query");
-
-    b.iter(|| {
-               res.get_body()
-                   .expect("get body")
-                   .into_rows()
-                   .expect("into rows");
-           })
-}
-
-#[bench]
-#[cfg(not(feature = "appveyor"))]
-fn list_convert(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_lists \
-               (my_text_list frozen<list<text>> PRIMARY KEY, \
-               my_nested_list list<frozen<list<int>>>)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_text_list = vec!["text1".to_string(),
-                            "text2".to_string(),
-                            "text3".to_string()];
-    let my_nested_list: Vec<Vec<i32>> =
-        vec![vec![1, 2, 3], vec![999, 888, 777, 666, 555], vec![-1, -2]];
-    let values: Vec<Value> = vec![my_text_list.clone().into(), my_nested_list.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_lists \
-               (my_text_list, my_nested_list) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_lists";
-    let query = QueryBuilder::new(cql).finalize();
-    let row = &session
-        .query(query, false, false)
-        .expect("query")
-        .get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows")
-        [0];
-
-    b.iter(|| {
-        let my_text_list_row: List = row.get_r_by_name("my_text_list").expect("my_text_list");
-        let my_text_list_row: Vec<String> =
-            my_text_list_row.as_r_rust().expect("my_text_list as rust");
-        let my_nested_list_outer_row: List = row.get_r_by_name("my_nested_list")
-            .expect("my_nested_list");
-        let my_nested_list_outer_row: Vec<List> = my_nested_list_outer_row
-            .as_r_rust()
-            .expect("my_nested_list (outer) as rust");
-        let mut my_nested_list_row = Vec::with_capacity(my_nested_list_outer_row.len());
-        for my_nested_list_inner_row in my_nested_list_outer_row {
-            let my_nested_list_inner_row: Vec<i32> = my_nested_list_inner_row
-                .as_r_rust()
-                .expect("my_nested_list (inner) as rust");
-            my_nested_list_row.push(my_nested_list_inner_row);
-        }
-    })
-}
-
-#[bench]
-#[cfg(feature = "v4")]
-#[cfg(not(feature = "appveyor"))]
-fn list_v4_body_parse(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_sets_v4 \
-               (my_text_set frozen<set<text>> PRIMARY KEY, \
-               my_nested_set set<frozen<set<smallint>>>)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_text_set = vec!["text1".to_string(),
-                           "text2".to_string(),
-                           "text3".to_string()];
-    let my_nested_set: Vec<Vec<i16>> =
-        vec![vec![-2, -1], vec![1, 2, 3], vec![555, 666, 777, 888, 999]];
-    let values: Vec<Value> = vec![my_text_set.clone().into(), my_nested_set.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_sets_v4 \
-               (my_text_set, my_nested_set) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_sets_v4";
-    let query = QueryBuilder::new(cql).finalize();
-    let res = session.query(query, false, false).expect("query");
-
-    b.iter(|| {
-               res.get_body()
-                   .expect("get body")
-                   .into_rows()
-                   .expect("into rows");
-           })
-}
-
-#[bench]
-#[cfg(feature = "v4")]
-#[cfg(not(feature = "appveyor"))]
-fn list_v4_convert(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_sets_v4 \
-               (my_text_set frozen<set<text>> PRIMARY KEY, \
-               my_nested_set set<frozen<set<smallint>>>)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_text_set = vec!["text1".to_string(),
-                           "text2".to_string(),
-                           "text3".to_string()];
-    let my_nested_set: Vec<Vec<i16>> =
-        vec![vec![-2, -1], vec![1, 2, 3], vec![555, 666, 777, 888, 999]];
-    let values: Vec<Value> = vec![my_text_set.clone().into(), my_nested_set.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_sets_v4 \
-               (my_text_set, my_nested_set) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_sets_v4";
-    let query = QueryBuilder::new(cql).finalize();
-    let row = &session
-        .query(query, false, false)
-        .expect("query")
-        .get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows")
-        [0];
-
-    b.iter(|| {
-        let my_text_set_row: List = row.get_r_by_name("my_text_set").expect("my_text_set");
-        let my_text_set_row: Vec<String> =
-            my_text_set_row.as_r_rust().expect("my_text_set as rust");
-        let my_nested_set_outer_row: List = row.get_r_by_name("my_nested_set")
-            .expect("my_nested_set");
-        let my_nested_set_outer_row: Vec<List> = my_nested_set_outer_row
-            .as_r_rust()
-            .expect("my_nested_set (outer) as rust");
-        let mut my_nested_set_row = Vec::with_capacity(my_nested_set_outer_row.len());
-        for my_nested_set_inner_row in my_nested_set_outer_row {
-            let my_nested_set_inner_row: Vec<i16> = my_nested_set_inner_row
-                .as_r_rust()
-                .expect("my_nested_set (inner) as rust");
-            my_nested_set_row.push(my_nested_set_inner_row);
-        }
-    })
-}
-
-#[bench]
-#[cfg(not(feature = "appveyor"))]
-fn map_without_blob_body_parse(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_maps_without_blob \
-               (my_key int PRIMARY KEY, \
-               my_text_map map<text, text>, \
-               my_nested_map map<uuid, frozen<map<bigint, int>>>)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_text_map =
-        hashmap!{
-        "key1".to_string() => "value1".to_string(),
-        "key2".to_string() => "value2".to_string(),
-        "key3".to_string() => "value3".to_string(),
-    };
-    let my_nested_map: HashMap<Uuid, HashMap<i64, i32>> =
-        hashmap!{
-        Uuid::from_str("bb16106a-10bc-4a07-baa3-126ffe208c43").unwrap() => hashmap!{
-            1 => 1,
-            2 => 2,
-        },
-        Uuid::from_str("687d7677-dbf0-4d25-8cf3-e5d9185bba0b").unwrap() => hashmap!{
-            1 => 1,
-        },
-        Uuid::from_str("c4dc6e8b-758a-4af4-ab00-ec356fb688d9").unwrap() => hashmap!{
-            1 => 1,
-            2 => 2,
-            3 => 3,
-        },
-    };
-    let values: Vec<Value> = vec![0i32.into(),
-                                  my_text_map.clone().into(),
-                                  my_nested_map.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_maps_without_blob \
-               (my_key, my_text_map, my_nested_map) VALUES (?, ?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_maps_without_blob";
-    let query = QueryBuilder::new(cql).finalize();
-    let res = session.query(query, false, false).expect("query");
-
-    b.iter(|| {
-               res.get_body()
-                   .expect("get body")
-                   .into_rows()
-                   .expect("into rows");
-           })
-}
-
-#[bench]
-#[cfg(not(feature = "appveyor"))]
-fn map_without_blob_convert(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_maps_without_blob \
-               (my_key int PRIMARY KEY, \
-               my_text_map map<text, text>, \
-               my_nested_map map<uuid, frozen<map<bigint, int>>>)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_text_map =
-        hashmap!{
-        "key1".to_string() => "value1".to_string(),
-        "key2".to_string() => "value2".to_string(),
-        "key3".to_string() => "value3".to_string(),
-    };
-    let my_nested_map: HashMap<Uuid, HashMap<i64, i32>> =
-        hashmap!{
-        Uuid::from_str("bb16106a-10bc-4a07-baa3-126ffe208c43").unwrap() => hashmap!{
-            1 => 1,
-            2 => 2,
-        },
-        Uuid::from_str("687d7677-dbf0-4d25-8cf3-e5d9185bba0b").unwrap() => hashmap!{
-            1 => 1,
-        },
-        Uuid::from_str("c4dc6e8b-758a-4af4-ab00-ec356fb688d9").unwrap() => hashmap!{
-            1 => 1,
-            2 => 2,
-            3 => 3,
-        },
-    };
-    let values: Vec<Value> = vec![0i32.into(),
-                                  my_text_map.clone().into(),
-                                  my_nested_map.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_maps_without_blob \
-               (my_key, my_text_map, my_nested_map) VALUES (?, ?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_maps_without_blob";
-    let query = QueryBuilder::new(cql).finalize();
-    let row = &session
-        .query(query, false, false)
-        .expect("query")
-        .get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows")
-        [0];
-
-    b.iter(|| {
-        let my_text_map_row: Map = row.get_r_by_name("my_text_map").expect("my_text_map");
-        let my_text_map_row: HashMap<String, String> =
-            my_text_map_row.as_r_rust().expect("my_text_map as rust");
-        let my_nested_map_outer_row: Map = row.get_r_by_name("my_nested_map")
-            .expect("my_nested_map");
-        let my_nested_map_outer_row: HashMap<Uuid, Map> =
-            my_nested_map_outer_row
-                .as_r_rust()
-                .expect("my_nested_map (outer) as rust");
-        let mut my_nested_map_row = HashMap::with_capacity(my_nested_map_outer_row.len());
-        for (index, my_nested_map_inner_row) in my_nested_map_outer_row {
-            let my_nested_map_inner_row: HashMap<i64, i32> =
-                my_nested_map_inner_row
-                    .as_r_rust()
-                    .expect("my_nested_map (inner) as rust");
-            my_nested_map_row.insert(index, my_nested_map_inner_row);
-        }
-    })
-}
-
-#[bench]
-#[cfg(not(feature = "appveyor"))]
-fn map_body_parse(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_maps \
-               (my_text_map frozen<map<text, text>> PRIMARY KEY, \
-               my_nested_map map<uuid, frozen<map<bigint, blob>>>)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_text_map =
-        hashmap!{
-        "key1".to_string() => "value1".to_string(),
-        "key2".to_string() => "value2".to_string(),
-        "key3".to_string() => "value3".to_string(),
-    };
-    let my_nested_map: HashMap<Uuid, HashMap<i64, Vec<u8>>> =
-        hashmap!{
-        Uuid::from_str("bb16106a-10bc-4a07-baa3-126ffe208c43").unwrap() => hashmap!{
-            1 => vec![52, 121, 209, 200, 81, 118, 181, 17],
-            2 => vec![226, 90, 51, 10, 26, 87, 141, 61],
-        },
-        Uuid::from_str("687d7677-dbf0-4d25-8cf3-e5d9185bba0b").unwrap() => hashmap!{
-            1 => vec![224, 155, 148, 6, 217, 96, 120, 38],
-        },
-        Uuid::from_str("c4dc6e8b-758a-4af4-ab00-ec356fb688d9").unwrap() => hashmap!{
-            1 => vec![164, 238, 196, 10, 149, 169, 145, 239],
-            2 => vec![250, 87, 119, 134, 105, 236, 240, 64],
-            3 => vec![72, 81, 26, 173, 107, 96, 38, 91],
-        },
-    };
-    let values: Vec<Value> = vec![my_text_map.clone().into(), my_nested_map.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_maps \
-               (my_text_map, my_nested_map) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_maps";
-    let query = QueryBuilder::new(cql).finalize();
-    let res = session.query(query, false, false).expect("query");
-
-    b.iter(|| {
-               res.get_body()
-                   .expect("get body")
-                   .into_rows()
-                   .expect("into rows");
-           })
-}
-
-#[bench]
-#[cfg(not(feature = "appveyor"))]
-fn map_convert(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_maps \
-               (my_text_map frozen<map<text, text>> PRIMARY KEY, \
-               my_nested_map map<uuid, frozen<map<bigint, blob>>>)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_text_map =
-        hashmap!{
-        "key1".to_string() => "value1".to_string(),
-        "key2".to_string() => "value2".to_string(),
-        "key3".to_string() => "value3".to_string(),
-    };
-    let my_nested_map: HashMap<Uuid, HashMap<i64, Vec<u8>>> =
-        hashmap!{
-        Uuid::from_str("bb16106a-10bc-4a07-baa3-126ffe208c43").unwrap() => hashmap!{
-            1 => vec![52, 121, 209, 200, 81, 118, 181, 17],
-            2 => vec![226, 90, 51, 10, 26, 87, 141, 61],
-        },
-        Uuid::from_str("687d7677-dbf0-4d25-8cf3-e5d9185bba0b").unwrap() => hashmap!{
-            1 => vec![224, 155, 148, 6, 217, 96, 120, 38],
-        },
-        Uuid::from_str("c4dc6e8b-758a-4af4-ab00-ec356fb688d9").unwrap() => hashmap!{
-            1 => vec![164, 238, 196, 10, 149, 169, 145, 239],
-            2 => vec![250, 87, 119, 134, 105, 236, 240, 64],
-            3 => vec![72, 81, 26, 173, 107, 96, 38, 91],
-        },
-    };
-    let values: Vec<Value> = vec![my_text_map.clone().into(), my_nested_map.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_maps \
-               (my_text_map, my_nested_map) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_maps";
-    let query = QueryBuilder::new(cql).finalize();
-    let row = &session
-        .query(query, false, false)
-        .expect("query")
-        .get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows")
-        [0];
-
-    b.iter(|| {
-        let my_text_map_row: Map = row.get_r_by_name("my_text_map").expect("my_text_map");
-        let my_text_map_row: HashMap<String, String> =
-            my_text_map_row.as_r_rust().expect("my_text_map as rust");
-        let my_nested_map_outer_row: Map = row.get_r_by_name("my_nested_map")
-            .expect("my_nested_map");
-        let my_nested_map_outer_row: HashMap<Uuid, Map> =
-            my_nested_map_outer_row
-                .as_r_rust()
-                .expect("my_nested_map (outer) as rust");
-        let mut my_nested_map_row = HashMap::with_capacity(my_nested_map_outer_row.len());
-        for (index, my_nested_map_inner_row) in my_nested_map_outer_row {
-            let my_nested_map_inner_row: HashMap<i64, Vec<u8>> =
-                my_nested_map_inner_row
-                    .as_r_rust()
-                    .expect("my_nested_map (inner) as rust");
-            my_nested_map_row.insert(index, my_nested_map_inner_row);
-        }
-    })
-}
diff --git a/benches/common/mod.rs b/benches/common/mod.rs
deleted file mode 100644
index 467b7a8..0000000
--- a/benches/common/mod.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-use regex::Regex;
-use cdrs::client::{CDRS, Session};
-use cdrs::query::QueryBuilder;
-use cdrs::authenticators::NoneAuthenticator;
-use cdrs::compression::Compression;
-use cdrs::transport::TransportTcp;
-use cdrs::error::Result;
-
-const ADDR: &'static str = "127.0.0.1:9042";
-
-pub type CSession = Session<NoneAuthenticator, TransportTcp>;
-
-pub fn setup(create_table_cql: &'static str) -> Result<CSession> {
-    setup_multiple(&[create_table_cql])
-}
-
-pub fn setup_multiple(create_cqls: &[&'static str]) -> Result<CSession> {
-    let authenticator = NoneAuthenticator;
-    let tcp_transport = TransportTcp::new(ADDR)?;
-    let client = CDRS::new(tcp_transport, authenticator);
-    let mut session = client.start(Compression::None)?;
-    let re_table_name = Regex::new(r"CREATE TABLE IF NOT EXISTS (\w+\.\w+)").unwrap();
-
-    let cql = "CREATE KEYSPACE IF NOT EXISTS cdrs_test WITH \
-               replication = {'class': 'SimpleStrategy', 'replication_factor': 1} \
-               AND durable_writes = false";
-    let query = QueryBuilder::new(cql).finalize();
-    session.query(query, true, true)?;
-
-    for create_cql in create_cqls.iter() {
-        let table_name = re_table_name
-            .captures(create_cql)
-            .map(|cap| cap.get(1).unwrap().as_str());
-
-        // Re-using tables is a lot faster than creating/dropping them for every test.
-        // But if table definitions change while editing tests
-        // the old tables need to be dropped. For example by uncommenting the following lines.
-        // if let Some(table_name) = table_name {
-        //     let cql = format!("DROP TABLE IF EXISTS {}", table_name);
-        //     let query = QueryBuilder::new(cql).finalize();
-        //     session.query(query, true, true)?;
-        // }
-
-        let query = QueryBuilder::new(create_cql.to_owned()).finalize();
-        session.query(query, true, true)?;
-
-        if let Some(table_name) = table_name {
-            let cql = format!("TRUNCATE TABLE {}", table_name);
-            let query = QueryBuilder::new(cql).finalize();
-            session.query(query, true, true)?;
-        }
-    }
-
-    Ok(session)
-}
diff --git a/benches/native_types.rs b/benches/native_types.rs
deleted file mode 100644
index d2fd5e9..0000000
--- a/benches/native_types.rs
+++ /dev/null
@@ -1,477 +0,0 @@
-#![feature(test)]
-extern crate test;
-
-extern crate cdrs;
-extern crate uuid;
-extern crate time;
-extern crate regex;
-
-use test::Bencher;
-
-mod common;
-
-use common::*;
-
-use uuid::Uuid;
-use cdrs::query::QueryBuilder;
-use cdrs::types::IntoRustByName;
-use cdrs::types::value::{Value, Bytes};
-
-use std::str::FromStr;
-use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-
-#[bench]
-#[cfg(not(feature = "appveyor"))]
-fn string_body_parse(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_string \
-               (my_ascii ascii PRIMARY KEY, my_text text, my_varchar varchar)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_ascii = "my_ascii".to_string();
-    let my_text = "my_text".to_string();
-    let my_varchar = "my_varchar".to_string();
-    let values: Vec<Value> = vec![my_ascii.clone().into(),
-                                  my_text.clone().into(),
-                                  my_varchar.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_string \
-               (my_ascii, my_text, my_varchar) VALUES (?, ?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_string";
-    let query = QueryBuilder::new(cql).finalize();
-    let res = session.query(query, false, false).expect("query");
-
-    b.iter(|| {
-               let _ = res.get_body()
-                   .expect("get body")
-                   .into_rows()
-                   .expect("into rows");
-           })
-}
-
-#[bench]
-fn string_convert(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_string \
-               (my_ascii ascii PRIMARY KEY, my_text text, my_varchar varchar)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_ascii = "my_ascii".to_string();
-    let my_text = "my_text".to_string();
-    let my_varchar = "my_varchar".to_string();
-    let values: Vec<Value> = vec![my_ascii.clone().into(),
-                                  my_text.clone().into(),
-                                  my_varchar.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_string \
-               (my_ascii, my_text, my_varchar) VALUES (?, ?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_string";
-    let query = QueryBuilder::new(cql).finalize();
-    let res = session.query(query, false, false).expect("query");
-    let ref row = res.get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows")
-        [0];
-
-    b.iter(|| {
-               let _: String = row.get_r_by_name("my_ascii").expect("my_ascii");
-               let _: String = row.get_r_by_name("my_text").expect("my_text");
-               let _: String = row.get_r_by_name("my_varchar").expect("my_varchar");
-           })
-}
-
-#[bench]
-fn counter_body_parse(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_counter \
-               (my_bigint bigint PRIMARY KEY, my_counter counter)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_bigint: i64 = 10_000_000_000_000_000;
-    let my_counter: i64 = 100_000_000;
-    let values: Vec<Value> = vec![my_counter.into(), my_bigint.into()];
-
-    let cql = "UPDATE cdrs_test.test_counter SET my_counter = my_counter + ? \
-               WHERE my_bigint = ?";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_counter";
-    let query = QueryBuilder::new(cql).finalize();
-    let res = session.query(query, false, false).expect("query");
-
-    b.iter(|| {
-               res.get_body()
-                   .expect("get body")
-                   .into_rows()
-                   .expect("into rows");
-           })
-}
-
-#[bench]
-fn counter_convert(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_counter \
-               (my_bigint bigint PRIMARY KEY, my_counter counter)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_bigint: i64 = 10_000_000_000_000_000;
-    let my_counter: i64 = 100_000_000;
-    let values: Vec<Value> = vec![my_counter.into(), my_bigint.into()];
-
-    let cql = "UPDATE cdrs_test.test_counter SET my_counter = my_counter + ? \
-               WHERE my_bigint = ?";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_counter";
-    let query = QueryBuilder::new(cql).finalize();
-    let row = &session
-        .query(query, false, false)
-        .expect("query")
-        .get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows")
-        [0];
-
-    b.iter(|| {
-               let _: i64 = row.get_r_by_name("my_bigint").expect("my_bigint");
-               let _: i64 = row.get_r_by_name("my_counter").expect("my_counter");
-           })
-}
-
-#[bench]
-fn integer_body_parse(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_integer \
-               (my_bigint bigint PRIMARY KEY, my_int int, my_boolean boolean)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_bigint: i64 = 10_000_000_000_000_000;
-    let my_int: i32 = 100_000_000;
-    let my_boolean: bool = true;
-    let values: Vec<Value> = vec![my_bigint.into(), my_int.into(), my_boolean.into()];
-
-    let cql = "INSERT INTO cdrs_test.test_integer \
-               (my_bigint, my_int, my_boolean) VALUES (?, ?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_integer";
-    let query = QueryBuilder::new(cql).finalize();
-    let res = session.query(query, false, false).expect("query");
-
-    b.iter(|| {
-               res.get_body()
-                   .expect("get body")
-                   .into_rows()
-                   .expect("into rows");
-           })
-}
-
-#[bench]
-fn integer_convert(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_integer \
-               (my_bigint bigint PRIMARY KEY, my_int int, my_boolean boolean)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_bigint: i64 = 10_000_000_000_000_000;
-    let my_int: i32 = 100_000_000;
-    let my_boolean: bool = true;
-    let values: Vec<Value> = vec![my_bigint.into(), my_int.into(), my_boolean.into()];
-
-    let cql = "INSERT INTO cdrs_test.test_integer \
-               (my_bigint, my_int, my_boolean) VALUES (?, ?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_integer";
-    let query = QueryBuilder::new(cql).finalize();
-    let row = &session
-        .query(query, false, false)
-        .expect("query")
-        .get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows")
-        [0];
-
-    b.iter(|| {
-               let _: i64 = row.get_r_by_name("my_bigint").expect("my_bigint");
-               let _: i32 = row.get_r_by_name("my_int").expect("my_int");
-               let _: bool = row.get_r_by_name("my_boolean").expect("my_boolean");
-           })
-}
-
-#[bench]
-fn float_body_parse(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_float \
-               (my_float float PRIMARY KEY, my_double double)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_float: f32 = 123.456;
-    let my_double: f64 = 987.654;
-    let values: Vec<Value> = vec![my_float.into(), my_double.into()];
-
-    let cql = "INSERT INTO cdrs_test.test_float (my_float, my_double) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_float";
-    let query = QueryBuilder::new(cql).finalize();
-    let res = session.query(query, false, false).expect("query");
-
-    b.iter(|| {
-               res.get_body()
-                   .expect("get body")
-                   .into_rows()
-                   .expect("into rows");
-           })
-}
-
-#[bench]
-fn float_convert(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_float \
-               (my_float float PRIMARY KEY, my_double double)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_float: f32 = 123.456;
-    let my_double: f64 = 987.654;
-    let values: Vec<Value> = vec![my_float.into(), my_double.into()];
-
-    let cql = "INSERT INTO cdrs_test.test_float (my_float, my_double) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_float";
-    let query = QueryBuilder::new(cql).finalize();
-    let row = &session
-        .query(query, false, false)
-        .expect("query")
-        .get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows")
-        [0];
-
-    b.iter(|| {
-               let _: f32 = row.get_r_by_name("my_float").expect("my_float");
-               let _: f64 = row.get_r_by_name("my_double").expect("my_double");
-           })
-}
-
-#[bench]
-fn blob_body_parse(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_blob \
-               (my_blob blob PRIMARY KEY)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_blob: Vec<u8> = vec![0, 1, 2, 4, 8, 16, 32, 64, 128, 255];
-    let values: Vec<Value> = vec![Bytes::new(my_blob.clone()).into()];
-
-    let cql = "INSERT INTO cdrs_test.test_blob (my_blob) VALUES (?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_blob";
-    let query = QueryBuilder::new(cql).finalize();
-    let res = session.query(query, false, false).expect("query");
-
-    b.iter(|| {
-               res.get_body()
-                   .expect("get body")
-                   .into_rows()
-                   .expect("into rows");
-           })
-}
-
-#[bench]
-fn blob_convert(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_blob \
-               (my_blob blob PRIMARY KEY)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_blob: Vec<u8> = vec![0, 1, 2, 4, 8, 16, 32, 64, 128, 255];
-    let values: Vec<Value> = vec![Bytes::new(my_blob.clone()).into()];
-
-    let cql = "INSERT INTO cdrs_test.test_blob (my_blob) VALUES (?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_blob";
-    let query = QueryBuilder::new(cql).finalize();
-    let row = &session
-        .query(query, false, false)
-        .expect("query")
-        .get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows")
-        [0];
-
-    b.iter(|| { let _: Vec<u8> = row.get_r_by_name("my_blob").expect("my_blob"); })
-}
-
-#[bench]
-fn uuid_body_parse(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_uuid \
-               (my_uuid uuid PRIMARY KEY)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_uuid = Uuid::from_str("bb16106a-10bc-4a07-baa3-126ffe208c43").unwrap();
-    let values: Vec<Value> = vec![my_uuid.into()];
-
-    let cql = "INSERT INTO cdrs_test.test_uuid (my_uuid) VALUES (?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_uuid";
-    let query = QueryBuilder::new(cql).finalize();
-    let res = session.query(query, false, false).expect("query");
-
-    b.iter(|| {
-               res.get_body()
-                   .expect("get body")
-                   .into_rows()
-                   .expect("into rows");
-           })
-}
-
-#[bench]
-fn uuid_convert(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_uuid \
-               (my_uuid uuid PRIMARY KEY)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_uuid = Uuid::from_str("bb16106a-10bc-4a07-baa3-126ffe208c43").unwrap();
-    let values: Vec<Value> = vec![my_uuid.into()];
-
-    let cql = "INSERT INTO cdrs_test.test_uuid (my_uuid) VALUES (?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_uuid";
-    let query = QueryBuilder::new(cql).finalize();
-    let row = &session
-        .query(query, false, false)
-        .expect("query")
-        .get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows")
-        [0];
-
-    b.iter(|| { let _: Uuid = row.get_r_by_name("my_uuid").expect("my_uuid"); })
-}
-
-#[bench]
-fn time_body_parse(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_time \
-               (my_timestamp timestamp PRIMARY KEY)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_timestamp = time::get_time();
-    let values: Vec<Value> = vec![my_timestamp.into()];
-
-    let cql = "INSERT INTO cdrs_test.test_time (my_timestamp) VALUES (?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_time";
-    let query = QueryBuilder::new(cql).finalize();
-    let res = session.query(query, false, false).expect("query");
-
-    b.iter(|| {
-               res.get_body()
-                   .expect("get body")
-                   .into_rows()
-                   .expect("into rows");
-           })
-}
-
-#[bench]
-fn time_convert(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_time \
-               (my_timestamp timestamp PRIMARY KEY)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_timestamp = time::get_time();
-    let values: Vec<Value> = vec![my_timestamp.into()];
-
-    let cql = "INSERT INTO cdrs_test.test_time (my_timestamp) VALUES (?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_time";
-    let query = QueryBuilder::new(cql).finalize();
-    let row = &session
-        .query(query, false, false)
-        .expect("query")
-        .get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows")
-        [0];
-
-    b.iter(|| { let _: time::Timespec = row.get_r_by_name("my_timestamp").expect("my_timestamp"); })
-}
-
-#[bench]
-fn inet_body_parse(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_inet \
-               (my_inet_v4 inet PRIMARY KEY, my_inet_v6 inet)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_inet_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
-    let my_inet_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
-    let values: Vec<Value> = vec![my_inet_v4.clone().into(), my_inet_v6.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_inet (my_inet_v4, my_inet_v6) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_inet";
-    let query = QueryBuilder::new(cql).finalize();
-    let res = session.query(query, false, false).expect("query");
-
-    b.iter(|| {
-               res.get_body()
-                   .expect("get body")
-                   .into_rows()
-                   .expect("into rows");
-           })
-}
-
-#[bench]
-fn inet_convert(b: &mut Bencher) {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_inet \
-               (my_inet_v4 inet PRIMARY KEY, my_inet_v6 inet)";
-    let mut session = setup(cql).expect("setup");
-
-    let my_inet_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
-    let my_inet_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
-    let values: Vec<Value> = vec![my_inet_v4.clone().into(), my_inet_v6.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_inet (my_inet_v4, my_inet_v6) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_inet";
-    let query = QueryBuilder::new(cql).finalize();
-    let row = &session
-        .query(query, false, false)
-        .expect("query")
-        .get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows")
-        [0];
-
-    b.iter(|| {
-               let _: IpAddr = row.get_r_by_name("my_inet_v4").expect("my_inet_v4");
-               let _: IpAddr = row.get_r_by_name("my_inet_v6").expect("my_inet_v6");
-           })
-}
diff --git a/examples/.gitignore b/examples/.gitignore
deleted file mode 100644
index e613873..0000000
--- a/examples/.gitignore
+++ /dev/null
@@ -1,1 +0,0 @@
-development.rs
diff --git a/examples/all.rs b/examples/all.rs
deleted file mode 100644
index d36a4a3..0000000
--- a/examples/all.rs
+++ /dev/null
@@ -1,1076 +0,0 @@
-
-extern crate cdrs;
-extern crate uuid;
-extern crate time;
-
-use uuid::Uuid;
-use std::convert::Into;
-use cdrs::IntoBytes;
-use cdrs::client::{CDRS, Session};
-use cdrs::consistency::Consistency;
-use cdrs::query::{QueryBuilder, QueryParamsBuilder};
-use cdrs::authenticators::NoneAuthenticator;
-use cdrs::compression::Compression;
-use cdrs::transport::TransportTcp;
-use cdrs::types::{IntoRustByName, CBytesShort, AsRust, ByName};
-use cdrs::types::value::{Value, Bytes};
-use cdrs::types::list::List;
-use cdrs::types::map::Map;
-use cdrs::types::udt::UDT;
-use cdrs::types::blob::Blob;
-use std::collections::HashMap;
-
-const _ADDR: &'static str = "127.0.0.1:9042";
-const CREATE_KEY_SPACE: &'static str = "CREATE KEYSPACE IF NOT EXISTS my_ks WITH REPLICATION = { \
-                                        'class' : 'SimpleStrategy', 'replication_factor' : 1 };";
-const CREATE_UDT: &'static str = "CREATE TYPE IF NOT EXISTS my_ks.my_type (number int);";
-const CREATE_TABLE_INT_V3: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.test_num (my_bigint \
-                                        bigint PRIMARY KEY, my_int int);";
-const CREATE_TABLE_INT: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.test_num (my_bigint \
-                                        bigint PRIMARY KEY, my_int int, my_smallint smallint, \
-                                        my_tinyint tinyint);";
-const CREATE_TABLE_STR: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.test_str (my_ascii \
-                                        ascii PRIMARY KEY, my_text text, my_varchar varchar);";
-const INSERT_STR: &'static str = "INSERT INTO my_ks.test_str (my_ascii, my_text, my_varchar) \
-                                  VALUES (?, ?, ?);";
-const SELECT_STR: &'static str = "SELECT * FROM my_ks.test_str;";
-const CREATE_TABLE_LIST_V3: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.lists (my_string_list \
-                                         list<text>, my_number_list \
-                                         list<int>, i int PRIMARY KEY);";
-const CREATE_TABLE_LIST: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.lists (my_string_list \
-                                         frozen<list<text>> PRIMARY KEY, my_number_list \
-                                         list<int>, my_complex_list list<frozen<list<smallint>>>);";
-const INSERT_LIST_V3: &'static str = "INSERT INTO my_ks.lists (my_string_list, \
-                                     my_number_list, i) VALUES (?, ?, ?);";
-const INSERT_LIST: &'static str = "INSERT INTO my_ks.lists (my_string_list, \
-                                   my_number_list, my_complex_list) VALUES (?, ?, ?);";
-const SELECT_LIST: &'static str = "SELECT * FROM my_ks.lists;";
-const CREATE_TABLE_MAP: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.maps \
-    (my_string_map frozen<map<text, text>> PRIMARY KEY, \
-     my_number_map map<text, int>, my_complex_map map<text, frozen<map<text, int>>>, \
-     my_int_key_map map<int, text>, my_uuid_key_map map<uuid, text>);";
-const CREATE_TABLE_MAP_V3: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.maps \
-         (i int PRIMARY KEY, \
-          my_string_map map<text, text>, \
-          my_number_map map<text, int>, \
-          my_int_key_map map<int, text>, my_uuid_key_map map<uuid, text>);";
-const INSERT_MAP: &'static str = "INSERT INTO my_ks.maps (my_string_map, my_number_map, \
-                                  my_complex_map, my_int_key_map, my_uuid_key_map) VALUES (?, ?, \
-                                  ?, ?, ?);";
-const INSERT_MAP_V3: &'static str = "INSERT INTO my_ks.maps (i, my_string_map, my_number_map, \
-                                     my_int_key_map, my_uuid_key_map) VALUES (?, ?, \
-                                     ?, ?, ?);";
-const SELECT_MAP: &'static str = "SELECT * FROM my_ks.maps;";
-const CREATE_TABLE_UDT: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.udts (my_key int \
-                                        PRIMARY KEY, my_udt my_type);";
-const CREATE_TABLE_UDT_V3: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.udts (my_key int \
-                                           PRIMARY KEY, my_udt frozen<my_type>);";
-const INSERT_UDT: &'static str = "INSERT INTO my_ks.udts (my_key, my_udt) VALUES (?, ?);";
-const SELECT_UDT: &'static str = "SELECT * FROM my_ks.udts;";
-const INSERT_INT_V3: &'static str = "INSERT INTO my_ks.test_num (my_bigint, my_int) VALUES (?, ?)";
-const INSERT_INT: &'static str = "INSERT INTO my_ks.test_num (my_bigint, my_int, my_smallint, \
-                                  my_tinyint) VALUES (?, ?, ?, ?)";
-const SELECT_INT: &'static str = "SELECT * FROM my_ks.test_num";
-const CREATE_TABLE_BOOL: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.bool (my_key int \
-                                        PRIMARY KEY, my_boolean boolean);";
-const INSERT_BOOL: &'static str = "INSERT INTO my_ks.bool (my_key, my_boolean) \
-                                    VALUES (?, ?);";
-const SELECT_BOOL: &'static str = "SELECT * FROM my_ks.bool;";
-const CREATE_TABLE_UUID: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.uuid (my_key int \
-                                        PRIMARY KEY, my_uuid uuid);";
-const INSERT_UUID: &'static str = "INSERT INTO my_ks.uuid (my_key, my_uuid) \
-                                    VALUES (?, ?);";
-const SELECT_UUID: &'static str = "SELECT * FROM my_ks.uuid;";
-const CREATE_TABLE_FLOAT: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.float (my_float float \
-                                        PRIMARY KEY, my_double double);";
-const INSERT_FLOAT: &'static str = "INSERT INTO my_ks.float (my_float, my_double) \
-                                    VALUES (?, ?);";
-const SELECT_FLOAT: &'static str = "SELECT * FROM my_ks.float;";
-const CREATE_TABLE_BLOB: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.blob (my_key int \
-                                        PRIMARY KEY, my_blob blob);";
-const INSERT_BLOB: &'static str = "INSERT INTO my_ks.blob (my_key, my_blob) \
-                                    VALUES (?, ?);";
-const SELECT_BLOB: &'static str = "SELECT * FROM my_ks.blob;";
-const CREATE_TABLE_TIMESTAMP: &'static str = "CREATE TABLE IF NOT EXISTS my_ks.timestamp \
-                                              (my_key int PRIMARY KEY, my_timestamp timestamp);";
-const INSERT_TIMESTAMP: &'static str = "INSERT INTO my_ks.timestamp (my_key, my_timestamp) \
-                                    VALUES (?, ?);";
-const SELECT_TIMESTAMP: &'static str = "SELECT * FROM my_ks.timestamp;";
-
-fn main() {
-    let authenticator = NoneAuthenticator;
-    let tcp_transport = TransportTcp::new(_ADDR).unwrap();
-    let client = CDRS::new(tcp_transport, authenticator);
-    let mut session = client.start(Compression::None).unwrap();
-
-    if create_keyspace(&mut session) {
-        println!("0. keyspace created");
-    }
-
-    if create_type(&mut session) {
-        println!("1. user type created");
-    }
-
-    if !cfg!(feature = "v3") {
-        if create_table_int(&mut session) {
-            println!("2. table int created");
-        }
-
-        let ref prepared_id = prepare_query(&mut session, INSERT_INT);
-
-        if insert_ints(&mut session, &prepared_id) {
-            println!("3. integers inserted");
-        }
-
-        if select_all_ints(&mut session) {
-            println!("4. integers selected");
-        }
-    } else {
-        if create_table_int_v3(&mut session) {
-            println!("2. table int created (v3)");
-        }
-
-        let ref prepared_id = prepare_query(&mut session, INSERT_INT_V3);
-
-        if insert_ints_v3(&mut session, &prepared_id) {
-            println!("3. integers inserted (v3)");
-        }
-
-        if select_all_ints_v3(&mut session) {
-            println!("4. integers selected (v3)");
-        }
-    }
-
-    if create_table_str(&mut session) {
-        println!("5. str table created");
-    }
-
-    if insert_table_str(&mut session) {
-        println!("6. str table inserted");
-    }
-
-    if insert_table_string(&mut session) {
-        println!("8. string table inserted");
-    }
-
-    if select_table_str(&mut session) {
-        println!("9. strings selected");
-    }
-
-    if cfg!(feature = "v3") {
-        if create_table_list_v3(&mut session) {
-            println!("10. list table created (v3)");
-        }
-
-        if insert_table_list_v3(&mut session) {
-            println!("11. list inserted (v3)");
-        }
-
-        if select_table_list_v3(&mut session) {
-            println!("12. list selected (v3)");
-        }
-    } else {
-        if create_table_list(&mut session) {
-            println!("10. list table created");
-        }
-
-        if insert_table_list(&mut session) {
-            println!("11. list inserted");
-        }
-
-        if select_table_list(&mut session) {
-            println!("12. list selected");
-        }
-    }
-
-    if cfg!(feature = "v3") {
-        if create_table_map_v3(&mut session) {
-            println!("13. map table created (v3)");
-        }
-
-        if insert_table_map_v3(&mut session) {
-            println!("14. map table inserted (v3)");
-        }
-
-        if select_table_map_v3(&mut session) {
-            println!("15. map table created (v3)");
-        }
-    } else {
-        if create_table_map(&mut session) {
-            println!("13. map table created");
-        }
-
-        if insert_table_map(&mut session) {
-            println!("14. map table inserted");
-        }
-
-        if select_table_map(&mut session) {
-            println!("15. map table created");
-        }
-    }
-
-    if cfg!(feature = "v3") {
-        if create_table_udt_v3(&mut session) {
-            println!("16. udt table created (v3)");
-        }
-    } else {
-        if create_table_udt_v3(&mut session) {
-            println!("16. udt table created");
-        }
-    }
-
-    if insert_table_udt(&mut session) {
-        println!("17. udt table inserted");
-    }
-
-    if select_table_udt(&mut session) {
-        println!("18. udt table selected");
-    }
-
-    if create_table_bool(&mut session) {
-        println!("19. bool table created");
-    }
-
-    if insert_table_bool(&mut session) {
-        println!("20. bool table inserted");
-    }
-
-    if select_table_bool(&mut session) {
-        println!("21. bool table selected");
-    }
-
-    if create_table_uuid(&mut session) {
-        println!("22. uuid table created");
-    }
-
-    if insert_table_uuid(&mut session) {
-        println!("23. uuid table inserted");
-    }
-
-    if select_table_uuid(&mut session) {
-        println!("24. uuid table selected");
-    }
-
-    if create_table_float(&mut session) {
-        println!("25. float table created");
-    }
-
-    if insert_table_float(&mut session) {
-        println!("26. float table inserted");
-    }
-
-    if select_table_float(&mut session) {
-        println!("27. float table selected");
-    }
-
-    if create_table_blob(&mut session) {
-        println!("28. blob table created");
-    }
-
-    if insert_table_blob(&mut session) {
-        println!("29. blob table inserted");
-    }
-
-    if select_table_blob(&mut session) {
-        println!("30. blob table selected");
-    }
-
-    if create_table_timestamp(&mut session) {
-        println!("31. timestamp table created");
-    }
-
-    if insert_table_timestamp(&mut session) {
-        println!("32. timestamp table inserted");
-    }
-
-    if select_table_timestamp(&mut session) {
-        println!("33. timestamp table selected");
-    }
-}
-
-fn create_keyspace(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_KEY_SPACE).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_keyspace {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn create_type(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_UDT).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_type {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn create_table_int(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_TABLE_INT).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_table_int {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn create_table_int_v3(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_TABLE_INT_V3).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_table_int_v3 {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn prepare_query(session: &mut Session<NoneAuthenticator, TransportTcp>,
-                 query: &'static str)
-                 -> CBytesShort {
-    session
-        .prepare(query.to_string(), false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_prepared()
-        .unwrap()
-        .id
-}
-
-fn insert_ints(session: &mut Session<NoneAuthenticator, TransportTcp>,
-               prepared_id: &CBytesShort)
-               -> bool {
-    let ints = Ints {
-        bigint: 123,
-        int: 234,
-        smallint: 256,
-        tinyint: 56,
-    };
-    let values_i: Vec<Value> = vec![ints.bigint.into(),
-                                    ints.int.into(),
-                                    ints.smallint.into(),
-                                    ints.tinyint.into()];
-
-    let execute_params = QueryParamsBuilder::new(Consistency::One)
-        .values(values_i)
-        .finalize();
-    let executed = session.execute(prepared_id, execute_params, false, false);
-    match executed {
-        Err(ref err) => panic!("executed int {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn insert_ints_v3(session: &mut Session<NoneAuthenticator, TransportTcp>,
-                  prepared_id: &CBytesShort)
-                  -> bool {
-    let ints = IntsV3 {
-        bigint: 123,
-        int: 234,
-    };
-    let values_i: Vec<Value> = vec![ints.bigint.into(), ints.int.into()];
-
-    let execute_params = QueryParamsBuilder::new(Consistency::One)
-        .values(values_i)
-        .finalize();
-    let executed = session.execute(prepared_id, execute_params, false, false);
-    match executed {
-        Err(ref err) => panic!("executed int v3 {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn select_all_ints(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let select_query = QueryBuilder::new(SELECT_INT).finalize();
-    let all = session
-        .query(select_query, false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_rows()
-        .unwrap();
-
-    for row in all {
-        let _ = Ints {
-            bigint: row.r_by_name("my_bigint").expect("my_bigint"),
-            int: row.r_by_name("my_int").expect("my_int"),
-            smallint: row.r_by_name("my_smallint").expect("my_smallint"),
-            tinyint: row.r_by_name("my_tinyint").expect("my_tinyint"),
-        };
-    }
-
-    true
-}
-
-fn select_all_ints_v3(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let select_query = QueryBuilder::new(SELECT_INT).finalize();
-    let all = session
-        .query(select_query, false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_rows()
-        .unwrap();
-
-    for row in all {
-        let _ = IntsV3 {
-            bigint: row.r_by_name("my_bigint").expect("my_bigint"),
-            int: row.r_by_name("my_int").expect("my_int"),
-        };
-    }
-
-    true
-}
-
-fn create_table_str(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_TABLE_STR).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_table str {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn insert_table_str(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let strs = Strs {
-        my_ascii: "my_ascii",
-        my_text: "my_text",
-        my_varchar: "my_varchar",
-    };
-    let values_s: Vec<Value> = vec![strs.my_ascii.into(),
-                                    strs.my_text.into(),
-                                    strs.my_varchar.into()];
-
-    let query = QueryBuilder::new(INSERT_STR).values(values_s).finalize();
-    let inserted = session.query(query, false, false);
-    match inserted {
-        Err(ref err) => panic!("inserted str {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn insert_table_string(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let strings = Strings {
-        my_ascii: "my_ascii".to_string(),
-        my_text: "my_text".to_string(),
-        my_varchar: "my_varchar".to_string(),
-    };
-    let values_s: Vec<Value> = vec![strings.my_ascii.into(),
-                                    strings.my_text.into(),
-                                    strings.my_varchar.into()];
-
-    let query = QueryBuilder::new(INSERT_STR).values(values_s).finalize();
-    let inserted = session.query(query, false, false);
-    match inserted {
-        Err(ref err) => panic!("inserted strings {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn select_table_str(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let select_query = QueryBuilder::new(SELECT_STR).finalize();
-    let all = session
-        .query(select_query, false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_rows()
-        .unwrap();
-
-    for row in all {
-        let _ = Strings {
-            my_ascii: row.r_by_name("my_ascii").expect("my_ascii"),
-            my_text: row.r_by_name("my_text").expect("my_text"),
-            my_varchar: row.r_by_name("my_varchar").expect("my_ascii"),
-        };
-    }
-
-    true
-}
-
-fn create_table_list_v3(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_TABLE_LIST_V3).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_table list {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn create_table_list(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_TABLE_LIST).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_table list {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn insert_table_list(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let lists = Lists {
-        string_list: vec!["hello".to_string(), "world".to_string()],
-        number_list: vec![1, 2, 3],
-        complex_list: vec![vec![1, 3, 4], vec![4, 5, 6]],
-    };
-
-
-    let values: Vec<Value> = vec![lists.string_list.into(),
-                                  lists.number_list.into(),
-                                  lists.complex_list.into()];
-
-    let query = QueryBuilder::new(INSERT_LIST).values(values).finalize();
-    let inserted = session.query(query, false, false);
-    match inserted {
-        Err(ref err) => panic!("inserted lists {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn insert_table_list_v3(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let lists = ListsV3 {
-        string_list: vec!["hello".to_string(), "world".to_string()],
-        number_list: vec![1, 2, 3],
-    };
-
-
-    let values: Vec<Value> = vec![lists.string_list.into(),
-                                  lists.number_list.into(),
-                                  (1 as i32).into()];
-
-    let query = QueryBuilder::new(INSERT_LIST_V3).values(values).finalize();
-    let inserted = session.query(query, false, false);
-    match inserted {
-        Err(ref err) => panic!("inserted lists (v3) {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn select_table_list(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let select_query = QueryBuilder::new(SELECT_LIST).finalize();
-    let all = session
-        .query(select_query, false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_rows()
-        .unwrap();
-
-    for row in all {
-        let _ = Lists {
-            string_list: row.r_by_name::<List>("my_string_list") // intermediate type is required
-                .expect("string_list")
-                .as_r_rust::<Vec<String>>() // final type is not required, it could be find
-                // authomatically
-                .expect("string_list"),
-            number_list: row.r_by_name::<List>("my_number_list")
-                .expect("number_list")
-                .as_r_rust()
-                .expect("number_list"),
-            complex_list: row.r_by_name::<List>("my_complex_list")
-                .expect("complex_list")
-                .as_r_rust::<Vec<List>>()
-                .expect("my_complex_list")
-                .iter()
-                .map(|it| it.as_r_rust().expect("number_list_c"))
-                .collect(),
-        };
-    }
-
-    true
-}
-
-fn select_table_list_v3(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let select_query = QueryBuilder::new(SELECT_LIST).finalize();
-    let all = session
-        .query(select_query, false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_rows()
-        .unwrap();
-
-    for row in all {
-        let _ = ListsV3 {
-            string_list: row.r_by_name::<List>("my_string_list") // intermediate type is required
-                .expect("string_list")
-                .as_r_rust::<Vec<String>>() // final type is not required, it could be find
-                // authomatically
-                .expect("string_list"),
-            number_list: row.r_by_name::<List>("my_number_list")
-                .expect("number_list")
-                .as_r_rust()
-                .expect("number_list"),
-        };
-    }
-
-    true
-}
-
-fn insert_table_map(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let mut string_map: HashMap<String, String> = HashMap::new();
-    string_map.insert("a".to_string(), "A".to_string());
-    let mut number_map: HashMap<String, i32> = HashMap::new();
-    number_map.insert("one".to_string(), 1);
-    let mut complex_map: HashMap<String, HashMap<String, i32>> = HashMap::new();
-    complex_map.insert("nested".to_string(), number_map.clone());
-    let mut int_key_map: HashMap<i32, String> = HashMap::new();
-    int_key_map.insert(1, "one".to_string());
-    let uuid: Uuid = Uuid::parse_str("6f586cab-cd6e-4b05-89a8-c7f27215adc8").unwrap();
-    let mut uuid_key_map: HashMap<Uuid, String> = HashMap::new();
-    uuid_key_map.insert(uuid, "random uuid".to_string());
-    let maps = Maps {
-        string_map: string_map,
-        number_map: number_map,
-        complex_map: complex_map,
-        int_key_map: int_key_map,
-        uuid_key_map: uuid_key_map,
-    };
-
-
-    let values: Vec<Value> = vec![maps.string_map.into(),
-                                  maps.number_map.into(),
-                                  maps.complex_map.into(),
-                                  maps.int_key_map.into(),
-                                  maps.uuid_key_map.into()];
-
-    let query = QueryBuilder::new(INSERT_MAP).values(values).finalize();
-    let inserted = session.query(query, false, false);
-    match inserted {
-        Err(ref err) => panic!("inserted maps {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn insert_table_map_v3(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let mut string_map: HashMap<String, String> = HashMap::new();
-    string_map.insert("a".to_string(), "A".to_string());
-
-    let mut number_map: HashMap<String, i32> = HashMap::new();
-    number_map.insert("one".to_string(), 1);
-
-    let mut int_key_map: HashMap<i32, String> = HashMap::new();
-    int_key_map.insert(1, "one".to_string());
-
-    let uuid: Uuid = Uuid::parse_str("6f586cab-cd6e-4b05-89a8-c7f27215adc8").unwrap();
-    let mut uuid_key_map: HashMap<Uuid, String> = HashMap::new();
-    uuid_key_map.insert(uuid, "random uuid".to_string());
-
-    let maps = MapsV3 {
-        string_map: string_map,
-        number_map: number_map,
-        int_key_map: int_key_map,
-        uuid_key_map: uuid_key_map,
-    };
-
-
-    let values: Vec<Value> = vec![(1 as i32).into(),
-                                  maps.string_map.into(),
-                                  maps.number_map.into(),
-                                  maps.int_key_map.into(),
-                                  maps.uuid_key_map.into()];
-
-    let query = QueryBuilder::new(INSERT_MAP_V3).values(values).finalize();
-    let inserted = session.query(query, false, false);
-    match inserted {
-        Err(ref err) => panic!("inserted maps (v3) {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn select_table_map(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-
-    let select_query = QueryBuilder::new(SELECT_MAP).finalize();
-    let all = session
-        .query(select_query, false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_rows()
-        .unwrap();
-
-    for row in all {
-        let _ = Maps {
-            string_map: row.r_by_name::<Map>("my_string_map")
-                .expect("string_map")
-                .as_r_rust()
-                .expect("string_map"),
-            number_map: row.r_by_name::<Map>("my_number_map")
-                .expect("number_map")
-                .as_r_rust()
-                .expect("number_map"),
-            complex_map: row.r_by_name::<Map>("my_complex_map")
-                .expect("complex_map")
-                .as_r_rust::<HashMap<String, Map>>()
-                .expect("my_complex_map")
-                .iter()
-                .fold(HashMap::new(), |mut hm, (k, v)| {
-                    hm.insert(k.clone(), v.as_r_rust().expect("complex_map_c"));
-                    hm
-                }),
-            int_key_map: row.r_by_name::<Map>("my_int_key_map")
-                .expect("int_key_map")
-                .as_r_rust()
-                .expect("int_key_map"),
-            uuid_key_map: row.r_by_name::<Map>("my_uuid_key_map")
-                .expect("uuid_key_map")
-                .as_r_rust()
-                .expect("uuid_key_map"),
-        };
-    }
-
-    true
-}
-
-fn select_table_map_v3(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-
-    let select_query = QueryBuilder::new(SELECT_MAP).finalize();
-    let all = session
-        .query(select_query, false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_rows()
-        .unwrap();
-
-    for row in all {
-        let _ = MapsV3 {
-            string_map: row.r_by_name::<Map>("my_string_map")
-                .expect("string_map")
-                .as_r_rust()
-                .expect("string_map"),
-            number_map: row.r_by_name::<Map>("my_number_map")
-                .expect("number_map")
-                .as_r_rust()
-                .expect("number_map"),
-            int_key_map: row.r_by_name::<Map>("my_int_key_map")
-                .expect("int_key_map")
-                .as_r_rust()
-                .expect("int_key_map"),
-            uuid_key_map: row.r_by_name::<Map>("my_uuid_key_map")
-                .expect("uuid_key_map")
-                .as_r_rust()
-                .expect("uuid_key_map"),
-        };
-    }
-
-    true
-}
-
-fn create_table_map(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_TABLE_MAP).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_table map {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn create_table_map_v3(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_TABLE_MAP_V3).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_table map (v3) {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn create_table_udt(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_TABLE_UDT).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_table udt {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn create_table_udt_v3(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_TABLE_UDT_V3).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_table udt (v3) {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn insert_table_udt(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let udt = Udt { number: 12 };
-    let values: Vec<Value> = vec![(1 as i32).into(), udt.into()];
-
-    let query = QueryBuilder::new(INSERT_UDT).values(values).finalize();
-    let inserted = session.query(query, false, false);
-    match inserted {
-        Err(ref err) => panic!("inserted udt {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn select_table_udt(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-
-    let select_query = QueryBuilder::new(SELECT_UDT).finalize();
-    let all = session
-        .query(select_query, false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_rows()
-        .unwrap();
-
-    for row in all {
-        let _ = Udt {
-            number: row.r_by_name::<UDT>("my_udt")
-                .expect("my_udt")
-                .r_by_name("number")
-                .expect("number"),
-        };
-    }
-
-    true
-}
-
-fn create_table_bool(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_TABLE_BOOL).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_table uuid {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn insert_table_bool(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let values: Vec<Value> = vec![(1 as i32).into(), false.into()];
-
-    let query = QueryBuilder::new(INSERT_BOOL).values(values).finalize();
-    let inserted = session.query(query, false, false);
-    match inserted {
-        Err(ref err) => panic!("inserted bool {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn select_table_bool(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-
-    let select_query = QueryBuilder::new(SELECT_BOOL).finalize();
-    let all = session
-        .query(select_query, false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_rows()
-        .unwrap();
-
-    for row in all {
-        let _: bool = row.r_by_name("my_boolean").expect("my_boolean");
-    }
-
-    true
-}
-
-fn create_table_uuid(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_TABLE_UUID).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_table uuid {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn insert_table_uuid(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let uuid: Uuid = Uuid::parse_str("0000002a-000c-0005-0c03-0938362b0809").unwrap();
-    let values: Vec<Value> = vec![(1 as i32).into(), uuid.into()];
-
-    let query = QueryBuilder::new(INSERT_UUID).values(values).finalize();
-    let inserted = session.query(query, false, false);
-    match inserted {
-        Err(ref err) => panic!("inserted UUID {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn select_table_uuid(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-
-    let select_query = QueryBuilder::new(SELECT_UUID).finalize();
-    let all = session
-        .query(select_query, false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_rows()
-        .unwrap();
-
-    for row in all {
-        let _: Uuid = row.r_by_name("my_uuid").expect("my_uuid");
-    }
-
-    true
-}
-
-fn create_table_float(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_TABLE_FLOAT).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_table float {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn insert_table_float(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let float: f32 = 4321.0;
-    let double: f64 = 1234.0;
-    let values: Vec<Value> = vec![float.into(), double.into()];
-
-    let query = QueryBuilder::new(INSERT_FLOAT).values(values).finalize();
-    let inserted = session.query(query, false, false);
-    match inserted {
-        Err(ref err) => panic!("inserted float {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn select_table_float(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-
-    let select_query = QueryBuilder::new(SELECT_FLOAT).finalize();
-    let all = session
-        .query(select_query, false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_rows()
-        .unwrap();
-
-    for row in all {
-        let _: f32 = row.r_by_name("my_float").expect("my_float");
-        let _: f64 = row.r_by_name("my_double").expect("my_double");
-    }
-
-    true
-}
-
-fn create_table_blob(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_TABLE_BLOB).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_table blob {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn insert_table_blob(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let blob: Blob = vec![0, 1, 2, 4, 8, 16, 32, 64, 128, 255].into();
-    let values: Vec<Value> = vec![(1 as i32).into(), blob.into()];
-
-    let query = QueryBuilder::new(INSERT_BLOB).values(values).finalize();
-    let inserted = session.query(query, false, false);
-    match inserted {
-        Err(ref err) => panic!("inserted blob {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn select_table_blob(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let select_query = QueryBuilder::new(SELECT_BLOB).finalize();
-    let all = session
-        .query(select_query, false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_rows()
-        .unwrap();
-
-    for row in all {
-        let _: Blob = row.r_by_name("my_blob").expect("my_blob");
-    }
-
-    true
-}
-
-fn create_table_timestamp(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let q = QueryBuilder::new(CREATE_TABLE_TIMESTAMP).finalize();
-    match session.query(q, false, false) {
-        Err(ref err) => panic!("create_table timestamp {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn insert_table_timestamp(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let timestamp = time::get_time();
-    let values: Vec<Value> = vec![(1 as i32).into(), timestamp.into()];
-
-    let query = QueryBuilder::new(INSERT_TIMESTAMP)
-        .values(values)
-        .finalize();
-    let inserted = session.query(query, false, false);
-    match inserted {
-        Err(ref err) => panic!("inserted timestamp {:?}", err),
-        Ok(_) => true,
-    }
-}
-
-fn select_table_timestamp(session: &mut Session<NoneAuthenticator, TransportTcp>) -> bool {
-    let select_query = QueryBuilder::new(SELECT_TIMESTAMP).finalize();
-    let all = session
-        .query(select_query, false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_rows()
-        .unwrap();
-
-    for row in all {
-        let _: time::Timespec = row.r_by_name("my_timestamp").expect("my_timestamp");
-    }
-
-    true
-}
-
-struct Ints {
-    pub bigint: i64,
-    pub int: i32,
-    pub smallint: i16,
-    pub tinyint: i8,
-}
-
-struct IntsV3 {
-    pub bigint: i64,
-    pub int: i32,
-}
-
-struct Strs<'a> {
-    pub my_ascii: &'a str,
-    pub my_text: &'a str,
-    pub my_varchar: &'a str,
-}
-
-struct Strings {
-    pub my_ascii: String,
-    pub my_text: String,
-    pub my_varchar: String,
-}
-
-#[derive(Debug)]
-struct Lists {
-    pub string_list: Vec<String>,
-    pub number_list: Vec<i32>,
-    pub complex_list: Vec<Vec<i16>>,
-}
-
-#[derive(Debug)]
-struct ListsV3 {
-    pub string_list: Vec<String>,
-    pub number_list: Vec<i32>,
-}
-
-#[derive(Debug)]
-struct Maps {
-    pub string_map: HashMap<String, String>,
-    pub number_map: HashMap<String, i32>,
-    pub complex_map: HashMap<String, HashMap<String, i32>>,
-    pub int_key_map: HashMap<i32, String>,
-    pub uuid_key_map: HashMap<Uuid, String>,
-}
-
-#[derive(Debug)]
-struct MapsV3 {
-    pub string_map: HashMap<String, String>,
-    pub number_map: HashMap<String, i32>,
-    pub int_key_map: HashMap<i32, String>,
-    pub uuid_key_map: HashMap<Uuid, String>,
-}
-
-#[derive(Debug)]
-struct Udt {
-    pub number: i32,
-}
-
-impl Into<Bytes> for Udt {
-    fn into(self) -> Bytes {
-        let mut bytes: Vec<u8> = vec![];
-        let val_bytes: Bytes = self.number.into();
-        bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
-        Bytes::new(bytes)
-    }
-}
diff --git a/examples/batch_queries.rs b/examples/batch_queries.rs
deleted file mode 100644
index 1abeab5..0000000
--- a/examples/batch_queries.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-
-extern crate cdrs;
-
-use cdrs::client::CDRS;
-use cdrs::query::BatchQueryBuilder;
-use cdrs::authenticators::PasswordAuthenticator;
-use cdrs::compression::Compression;
-use cdrs::transport::TransportTcp;
-// default credentials
-const _USER: &'static str = "cassandra";
-const _PASS: &'static str = "cassandra";
-const _ADDR: &'static str = "127.0.0.1:9042";
-
-/// First create a keyspace 'keyspace'.
-/// Then create a new table of integers:
-/// CREATE TABLE keyspace.integers (integer int PRIMARY KEY);
-
-
-fn main() {
-    let authenticator = PasswordAuthenticator::new(_USER, _PASS);
-    let tcp_transport = TransportTcp::new(_ADDR).unwrap();
-    let client = CDRS::new(tcp_transport, authenticator);
-    let session = client.start(Compression::None).unwrap();
-
-    let prepare_query = "INSERT INTO keyspace.integers (integer) VALUES (1);".to_string();
-    let with_tracing = false;
-    let with_warnings = false;
-
-    let prepared = session
-        .prepare(prepare_query, with_tracing, with_warnings)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_prepared()
-        .unwrap();
-
-    let run = "INSERT INTO keyspace.integers (integer) VALUES (2);".to_string();
-
-    let batch_query = BatchQueryBuilder::new()
-        .add_query_prepared(prepared.id.clone(), vec![])
-        .add_query(run, vec![])
-        .finalize()
-        .unwrap();
-
-    let batched = session.batch(batch_query, false, false).unwrap();
-
-    println!("batch result {:?}", batched.get_body());
-}
diff --git a/examples/cluster.rs b/examples/cluster.rs
deleted file mode 100644
index e9524fb..0000000
--- a/examples/cluster.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-
-extern crate cdrs;
-extern crate r2d2;
-
-use std::thread;
-use std::sync::mpsc::channel;
-
-use cdrs::cluster::{LoadBalancingStrategy, LoadBalancer, ClusterConnectionManager};
-use cdrs::authenticators::PasswordAuthenticator;
-use cdrs::compression::Compression;
-use cdrs::query::QueryBuilder;
-use cdrs::transport::TransportTcp;
-
-// default credentials
-const _USER: &'static str = "cassandra";
-const _PASS: &'static str = "cassandra";
-const _ADDR1: &'static str = "127.0.0.1:9042";
-const _ADDR2: &'static str = "127.0.0.1:9043";
-
-fn main() {
-    // TODO: setup cluster with different nodes and test it
-    let cluster = vec![_ADDR1, _ADDR2]
-        .iter()
-        .map(|addr| TransportTcp::new(addr).unwrap())
-        .collect();
-    let authenticator = PasswordAuthenticator::new(_USER, _PASS);
-    let load_balancer = LoadBalancer::new(cluster, LoadBalancingStrategy::RoundRobin);
-    let manager = ClusterConnectionManager::new(load_balancer, authenticator, Compression::None);
-    let pool = r2d2::Pool::builder().max_size(15).build(manager).unwrap();
-
-    let (tx, rx) = channel();
-    for i in 0..20 {
-        let tx = tx.clone();
-        let pool = pool.clone();
-
-        thread::spawn(move || {
-            let query = QueryBuilder::new("SELECT * FROM system.peers;").finalize();
-            let conn = pool.get().unwrap();
-            let res = if conn.query(query, false, false).is_ok() {
-                format!("Thread #{} - ok", i)
-            } else {
-                format!("Thread #{} - err", i)
-            };
-
-            tx.send(res).unwrap();
-        });
-    }
-
-    for _ in 0..20 {
-        let res = rx.recv().unwrap();
-        println!("{:?}", res);
-    }
-}
diff --git a/examples/connection_pool.rs b/examples/connection_pool.rs
deleted file mode 100644
index 3dba664..0000000
--- a/examples/connection_pool.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-
-extern crate cdrs;
-extern crate r2d2;
-
-use std::thread;
-use std::sync::mpsc::channel;
-
-use cdrs::connection_manager::ConnectionManager;
-use cdrs::authenticators::PasswordAuthenticator;
-use cdrs::compression::Compression;
-use cdrs::query::QueryBuilder;
-use cdrs::transport::TransportTcp;
-
-// default credentials
-const _USER: &'static str = "cassandra";
-const _PASS: &'static str = "cassandra";
-const _ADDR: &'static str = "127.0.0.1:9042";
-
-fn main() {
-    let transport = TransportTcp::new(_ADDR).unwrap();
-    let authenticator = PasswordAuthenticator::new(_USER, _PASS);
-    let manager = ConnectionManager::new(transport, authenticator, Compression::None);
-    let pool = r2d2::Pool::builder().max_size(15).build(manager).unwrap();
-
-    let (tx, rx) = channel();
-    for i in 0..20 {
-        let tx = tx.clone();
-        let pool = pool.clone();
-
-        thread::spawn(move || {
-            let query = QueryBuilder::new("SELECT * FROM system.peers;").finalize();
-            let conn = pool.get().unwrap();
-            let res = if conn.query(query, false, false).is_ok() {
-                format!("Thread #{} - ok", i)
-            } else {
-                format!("Thread #{} - err", i)
-            };
-
-            tx.send(res).unwrap();
-        });
-    }
-
-    for _ in 0..20 {
-        let res = rx.recv().unwrap();
-        println!("{:?}", res);
-    }
-}
diff --git a/examples/create_table.rs b/examples/create_table.rs
deleted file mode 100644
index 34ef420..0000000
--- a/examples/create_table.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-
-extern crate cdrs;
-
-use cdrs::client::CDRS;
-use cdrs::query::QueryBuilder;
-use cdrs::authenticators::PasswordAuthenticator;
-use cdrs::compression::Compression;
-use cdrs::consistency::Consistency;
-use cdrs::transport::TransportTcp;
-// default credentials
-const _USER: &'static str = "cassandra";
-const _PASS: &'static str = "cassandra";
-const _ADDR: &'static str = "127.0.0.1:9042";
-
-
-fn main() {
-    let authenticator = PasswordAuthenticator::new(_USER, _PASS);
-    let tcp_transport = TransportTcp::new(_ADDR).unwrap();
-    let client = CDRS::new(tcp_transport, authenticator);
-    let session = client.start(Compression::None).unwrap();
-
-    // NOTE: keyspace "keyspace" should already exist
-    let create_table_cql = "CREATE TABLE keyspace.users (
-        user_name varchar PRIMARY KEY,
-        password varchar,
-        gender varchar,
-        session_token varchar,
-        state varchar,
-        birth_year bigint
-    );";
-    let create_table_query = QueryBuilder::new(create_table_cql)
-        .consistency(Consistency::One)
-        .finalize();
-    let with_tracing = false;
-    let with_warnings = false;
-
-    match session.query(create_table_query, with_tracing, with_warnings) {
-        Ok(ref res) => println!("table created: {:?}", res.get_body()),
-        Err(ref err) => println!("Error occured: {:?}", err),
-    }
-}
diff --git a/examples/crud_operations.rs b/examples/crud_operations.rs
new file mode 100644
index 0000000..8744fd4
--- /dev/null
+++ b/examples/crud_operations.rs
@@ -0,0 +1,131 @@
+#[macro_use]
+extern crate cdrs;
+#[macro_use]
+extern crate cdrs_helpers_derive;
+#[macro_use]
+extern crate maplit;
+
+use std::collections::HashMap;
+
+use cdrs::authenticators::NoneAuthenticator;
+use cdrs::cluster::{Cluster, Session};
+use cdrs::query::*;
+use cdrs::load_balancing::{RoundRobin};
+use cdrs::transport::TransportTcp;
+
+use cdrs::types::prelude::*;
+use cdrs::types::from_cdrs::FromCDRSByName;
+use cdrs::frame::IntoBytes;
+
+type CurrentSession = Session<RoundRobin<TransportTcp>, NoneAuthenticator>;
+
+fn main() {
+  let cluster = Cluster::new(vec!["127.0.0.1:9042"], NoneAuthenticator {});
+  let mut no_compression = cluster
+    .connect(RoundRobin::new())
+    .expect("No compression connection error");
+
+  create_keyspace(&mut no_compression);
+  create_udt(&mut no_compression);
+  create_table(&mut no_compression);
+  insert_struct(&mut no_compression);
+  select_struct(&mut no_compression);
+  update_struct(&mut no_compression);
+  delete_struct(&mut no_compression);
+}
+
+#[derive(Clone, Debug, IntoCDRSValue, TryFromRow, PartialEq)]
+struct RowStruct {
+  key: i32,
+  user: User,
+  map: HashMap<String, User>,
+  list: Vec<User>,
+}
+
+impl RowStruct {
+  fn into_query_values(self) -> QueryValues {
+    query_values!("key" => self.key, "user" => self.user, "map" => self.map, "list" => self.list)
+  }
+}
+
+#[derive(Debug, Clone, PartialEq, IntoCDRSValue, TryFromUDT)]
+struct User {
+  username: String,
+}
+
+fn create_keyspace(session: &mut CurrentSession) {
+  let create_ks: &'static str = "CREATE KEYSPACE IF NOT EXISTS test_ks WITH REPLICATION = { \
+                                 'class' : 'SimpleStrategy', 'replication_factor' : 1 };";
+  session.query(create_ks).expect("Keyspace creation error");
+}
+
+fn create_udt(session: &mut CurrentSession) {
+  let create_type_cql = "CREATE TYPE IF NOT EXISTS test_ks.user (username text)";
+  session
+    .query(create_type_cql)
+    .expect("Keyspace creation error");
+}
+
+fn create_table(session: &mut CurrentSession) {
+  let create_table_cql = "CREATE TABLE IF NOT EXISTS test_ks.my_test_table (key int PRIMARY KEY, \
+                          user test_ks.user, map map<text, frozen<test_ks.user>>, list list<frozen<test_ks.user>>);";
+  session
+    .query(create_table_cql)
+    .expect("Table creation error");
+}
+
+fn insert_struct(session: &mut CurrentSession) {
+  let row = RowStruct {
+    key: 3i32,
+    user: User {
+      username: "John".to_string(),
+    },
+    map: hashmap! { "John".to_string() => User { username: "John".to_string() } },
+    list: vec![
+      User {
+        username: "John".to_string(),
+      },
+    ],
+  };
+
+  let insert_struct_cql = "INSERT INTO test_ks.my_test_table \
+                           (key, user, map, list) VALUES (?, ?, ?, ?)";
+  session
+    .query_with_values(insert_struct_cql, row.into_query_values())
+    .expect("insert");
+}
+
+fn select_struct(session: &mut CurrentSession) {
+  let select_struct_cql = "SELECT * FROM test_ks.my_test_table";
+  let rows = session
+    .query(select_struct_cql)
+    .expect("query")
+    .get_body()
+    .expect("get body")
+    .into_rows()
+    .expect("into rows");
+
+  for row in rows {
+    let my_row: RowStruct = RowStruct::try_from_row(row).expect("into RowStruct");
+    println!("struct got: {:?}", my_row);
+  }
+}
+
+fn update_struct(session: &mut CurrentSession) {
+  let update_struct_cql = "UPDATE test_ks.my_test_table SET user = ? WHERE key = ?";
+  let upd_user = User {
+    username: "Marry".to_string(),
+  };
+  let user_key = 1i32;
+  session
+    .query_with_values(update_struct_cql, query_values!(upd_user, user_key))
+    .expect("update");
+}
+
+fn delete_struct(session: &mut CurrentSession) {
+  let delete_struct_cql = "DELETE FROM test_ks.my_test_table WHERE key = ?";
+  let user_key = 1i32;
+  session
+    .query_with_values(delete_struct_cql, query_values!(user_key))
+    .expect("delete");
+}
diff --git a/examples/paged_query.rs b/examples/paged_query.rs
new file mode 100644
index 0000000..ca3a927
--- /dev/null
+++ b/examples/paged_query.rs
@@ -0,0 +1,83 @@
+#[macro_use]
+extern crate cdrs;
+#[macro_use]
+extern crate cdrs_helpers_derive;
+
+use cdrs::authenticators::NoneAuthenticator;
+use cdrs::cluster::{Cluster, Session};
+use cdrs::query::*;
+use cdrs::load_balancing::RoundRobin;
+use cdrs::transport::TransportTcp;
+
+use cdrs::types::prelude::*;
+use cdrs::types::from_cdrs::FromCDRSByName;
+use cdrs::frame::IntoBytes;
+
+type CurrentSession = Session<RoundRobin<TransportTcp>, NoneAuthenticator>;
+
+#[derive(Clone, Debug, IntoCDRSValue, TryFromRow, PartialEq)]
+struct RowStruct {
+  key: i32,
+}
+
+impl RowStruct {
+  fn into_query_values(self) -> QueryValues {
+    query_values!("key" => self.key)
+  }
+}
+
+fn main() {
+  let cluster = Cluster::new(vec!["127.0.0.1:9042"], NoneAuthenticator {});
+  let mut no_compression = cluster
+    .connect(RoundRobin::new())
+    .expect("No compression connection error");
+
+  create_keyspace(&mut no_compression);
+  create_table(&mut no_compression);
+  fill_table(&mut no_compression);
+  paged_selection_query(&mut no_compression);
+}
+
+fn create_keyspace(session: &mut CurrentSession) {
+  let create_ks: &'static str = "CREATE KEYSPACE IF NOT EXISTS test_ks WITH REPLICATION = { \
+                                 'class' : 'SimpleStrategy', 'replication_factor' : 1 };";
+  session.query(create_ks).expect("Keyspace creation error");
+}
+
+fn create_table(session: &mut CurrentSession) {
+  let create_table_cql = "CREATE TABLE IF NOT EXISTS test_ks.my_test_table (key int PRIMARY KEY, \
+                          user test_ks.user, map map<text, frozen<test_ks.user>>, list list<frozen<test_ks.user>>);";
+  session
+    .query(create_table_cql)
+    .expect("Table creation error");
+}
+
+fn fill_table(session: &mut CurrentSession) {
+  let insert_struct_cql = "INSERT INTO test_ks.my_test_table (key) VALUES (?)";
+
+  for k in 100..110 {
+    let row = RowStruct {key: k as i32};
+
+    session
+      .query_with_values(insert_struct_cql, row.into_query_values())
+      .expect("insert");
+  }
+}
+
+fn paged_selection_query(session: &mut CurrentSession) {
+  let q = "SELECT * FROM test_ks.my_test_table;";
+  let mut pager = session.paged(2);
+  let mut query_pager = pager.query(q);
+
+  loop {
+    let rows = query_pager.next().expect("pager next");
+    for row in rows {
+      let my_row = RowStruct::try_from_row(row).expect("decode row");
+      println!("row - {:?}", my_row);
+    }
+
+    if !query_pager.has_more() {
+      break;
+    }
+  }
+}
diff --git a/examples/prepare_batch_execute.rs b/examples/prepare_batch_execute.rs
new file mode 100644
index 0000000..910a3e9
--- /dev/null
+++ b/examples/prepare_batch_execute.rs
@@ -0,0 +1,87 @@
+#[macro_use]
+extern crate cdrs;
+#[macro_use]
+extern crate cdrs_helpers_derive;
+#[macro_use]
+extern crate maplit;
+
+use cdrs::authenticators::NoneAuthenticator;
+use cdrs::cluster::{Cluster, Session};
+use cdrs::query::*;
+use cdrs::load_balancing::RoundRobin;
+use cdrs::transport::TransportTcp;
+
+use cdrs::types::prelude::*;
+use cdrs::types::from_cdrs::FromCDRSByName;
+use cdrs::frame::IntoBytes;
+
+type CurrentSession = Session<RoundRobin<TransportTcp>, NoneAuthenticator>;
+
+#[derive(Clone, Debug, IntoCDRSValue, TryFromRow, PartialEq)]
+struct RowStruct {
+  key: i32,
+}
+
+impl RowStruct {
+  fn into_query_values(self) -> QueryValues {
+    /// **IMPORTANT NOTE:** query values should be WITHOUT NAMES
+    /// https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L413
+    query_values!(self.key)
+  }
+}
+
+fn main() {
+  let cluster = Cluster::new(vec!["127.0.0.1:9042"], NoneAuthenticator {});
+  let mut no_compression = cluster
+    .connect(RoundRobin::new())
+    .expect("No compression connection error");
+
+  create_keyspace(&mut no_compression);
+  create_table(&mut no_compression);
+
+  let insert_struct_cql = "INSERT INTO test_ks.my_test_table (key) VALUES (?)";
+  let prepared_query = no_compression
+    .prepare(insert_struct_cql)
+    .expect("Prepare query error");
+
+  for k in 100..110 {
+    let row = RowStruct { key: k as i32 };
+
+    insert_row(&mut no_compression, row, &prepared_query);
+  }
+
+  batch_few_queries(&mut no_compression, &insert_struct_cql);
+}
+
+fn create_keyspace(session: &mut CurrentSession) {
+  let create_ks: &'static str = "CREATE KEYSPACE IF NOT EXISTS test_ks WITH REPLICATION = { \
+                                 'class' : 'SimpleStrategy', 'replication_factor' : 1 };";
+  session.query(create_ks).expect("Keyspace creation error");
+}
+
+fn create_table(session: &mut CurrentSession) {
+  let create_table_cql = "CREATE TABLE IF NOT EXISTS test_ks.my_test_table (key int PRIMARY KEY);";
+  session
+    .query(create_table_cql)
+    .expect("Table creation error");
+}
+
+fn insert_row(session: &mut CurrentSession, row: RowStruct, prepared_query: &PreparedQuery) {
+  session
+    .exec_with_values(prepared_query, row.into_query_values())
+    .expect("exec_with_values error");
+}
+
+fn batch_few_queries(session: &mut CurrentSession, query: &str) {
+  let prepared_query = session.prepare(query).expect("Prepare query error");
+  let row_1 = RowStruct { key: 1001 as i32 };
+  let row_2 = RowStruct { key: 2001 as i32 };
+
+  let batch = BatchQueryBuilder::new()
+    .add_query_prepared(prepared_query, row_1.into_query_values())
+    .add_query(query, row_2.into_query_values())
+    .finalize()
+    .expect("batch builder");
+
+  session.batch_with_params(batch).expect("batch query error");
+}
diff --git a/examples/prepare_execute.rs b/examples/prepare_execute.rs
deleted file mode 100644
index e73e496..0000000
--- a/examples/prepare_execute.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-
-extern crate cdrs;
-
-use cdrs::client::CDRS;
-use cdrs::query::QueryParamsBuilder;
-use cdrs::authenticators::PasswordAuthenticator;
-use cdrs::compression::Compression;
-use cdrs::consistency::Consistency;
-use cdrs::transport::TransportTcp;
-// default credentials
-const _USER: &'static str = "cassandra";
-const _PASS: &'static str = "cassandra";
-const _ADDR: &'static str = "127.0.0.1:9042";
-
-
-fn main() {
-    let authenticator = PasswordAuthenticator::new(_USER, _PASS);
-    let tcp_transport = TransportTcp::new(_ADDR).unwrap();
-    let client = CDRS::new(tcp_transport, authenticator);
-    let session = client.start(Compression::None).unwrap();
-
-    // NOTE: keyspace "keyspace" should already exist
-    let create_table_cql = "USE keyspace;".to_string();
-    let with_tracing = false;
-    let with_warnings = false;
-
-    let prepared = session
-        .prepare(create_table_cql, with_tracing, with_warnings)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_prepared()
-        .unwrap();
-
-    println!("prepared:\n{:?}", prepared);
-
-    let execution_params = QueryParamsBuilder::new(Consistency::One).finalize();
-    let ref query_id = prepared.id;
-    let executed = session
-        .execute(query_id, execution_params, false, false)
-        .unwrap()
-        .get_body()
-        .unwrap()
-        .into_set_keyspace()
-        .unwrap();
-
-    println!("executed:\n{:?}", executed);
-}
diff --git a/examples/read_table_into_struct.rs b/examples/read_table_into_struct.rs
deleted file mode 100644
index e812bf2..0000000
--- a/examples/read_table_into_struct.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-extern crate cdrs;
-use cdrs::client::CDRS;
-use cdrs::query::QueryBuilder;
-use cdrs::authenticators::PasswordAuthenticator;
-use cdrs::compression::Compression;
-use cdrs::types::IntoRustByName;
-use cdrs::transport::TransportTcp;
-
-
-/// this example is to pull employee records from emp table
-///
-/// # Examples
-///
-/// ```
-/// CREATE KEYSPACE my_namespace WITH REPLICATION = { 'class' : 'SimpleStrategy',
-/// 'replication_factor' : 1 };
-
-/// CREATE TABLE my_namespace.emp(
-/// emp_id int PRIMARY KEY,
-/// emp_name text,
-/// emp_city text,
-/// emp_sal varint,
-/// emp_phone varint
-/// );
-
-/// INSERT INTO my_namespace.emp (emp_id, emp_name, emp_city,emp_phone, emp_sal)
-/// VALUES(1,'alex', 'NJ', 9848022338, 50000);
-/// INSERT INTO my_namespace.emp (emp_id, emp_name, emp_city,emp_phone, emp_sal)
-/// VALUES(2,'harry', 'FLL', 9848022338, 50000);
-///
-///
-/// ```
-#[derive(Debug, Default)]
-struct Employee {
-    pub id: i64,
-    pub emp_name: String,
-    pub emp_city: String,
-    pub emp_sal: i64,
-    pub emp_phone: i64,
-}
-
-fn main() {
-
-    let authenticator = PasswordAuthenticator::new("user", "pass");
-    let addr = "127.0.0.1:9042";
-    let tcp_transport = TransportTcp::new(addr).unwrap();
-
-    // pass authenticator into CDRS' constructor
-    let client = CDRS::new(tcp_transport, authenticator);
-
-    // start session without compression
-    let select_query = QueryBuilder::new("SELECT * FROM my_namespace.emp;").finalize();
-
-    match client.start(Compression::None) {
-        Ok(session) => {
-            let with_tracing = false;
-            let with_warnings = false;
-            let query_op = session.query(select_query, with_tracing, with_warnings);
-
-            match query_op {
-                Ok(res) => {
-                    let res_body = res.get_body().unwrap();
-                    if let Some(rows) = res_body.into_rows() {
-                        let employees: Vec<Employee> = rows.iter()
-                            .map(|row| {
-                                let mut employee = Employee { ..Default::default() };
-                                if let Ok(Some(id)) = row.get_by_name("emp_id") {
-                                    employee.id = id;
-                                }
-
-                                if let Ok(Some(emp_name)) = row.get_by_name("emp_name") {
-                                    employee.emp_name = emp_name;
-                                }
-
-                                if let Ok(Some(emp_city)) = row.get_by_name("emp_city") {
-                                    employee.emp_city = emp_city;
-                                }
-
-                                if let Ok(Some(emp_sal)) = row.get_by_name("emp_sal") {
-                                    employee.emp_sal = emp_sal;
-                                }
-
-                                if let Ok(Some(emp_phone)) = row.get_by_name("emp_phone") {
-                                    employee.emp_phone = emp_phone;
-                                }
-
-                                employee
-                            })
-                            .collect();
-                        println!("Employees {:?}", employees);
-                    }
-                }
-                Err(err) => println!("{:?}", err),
-            }
-        }
-        Err(err) => println!("{:?}", err),
-    }
-
-}
diff --git a/examples/server_events.rs b/examples/server_events.rs
index 561b2b6..96473be 100644
--- a/examples/server_events.rs
+++ b/examples/server_events.rs
@@ -1,38 +1,37 @@
-
 extern crate cdrs;
-extern crate r2d2;
 
 use std::thread;
+use std::iter::Iterator;
 
-use cdrs::client::CDRS;
-use cdrs::authenticators::PasswordAuthenticator;
-use cdrs::compression::Compression;
-use cdrs::frame::events::{SimpleServerEvent, ServerEvent, ChangeType, Target};
+use cdrs::authenticators::{Authenticator, NoneAuthenticator};
+use cdrs::cluster::{Cluster, Session};
+use cdrs::load_balancing::RoundRobin;
 use cdrs::transport::TransportTcp;
+use cdrs::compression::Compression;
+use cdrs::frame::events::{ChangeType, ServerEvent, SimpleServerEvent, Target};
 
-// default credentials
-const _USER: &'static str = "cassandra";
-const _PASS: &'static str = "cassandra";
 const _ADDR: &'static str = "127.0.0.1:9042";
 
+type CurrentSession = Session<RoundRobin<TransportTcp>, NoneAuthenticator>;
+
 fn main() {
-    let transport = TransportTcp::new(_ADDR).unwrap();
-    let authenticator = PasswordAuthenticator::new(_USER, _PASS);
-    let client = CDRS::new(transport, authenticator);
-    let session = client.start(Compression::None).unwrap();
+  let cluster = Cluster::new(vec!["127.0.0.1:9042"], NoneAuthenticator {});
+  let mut no_compression = cluster
+    .connect(RoundRobin::new())
+    .expect("No compression connection error");
 
-    let (mut listener, stream) = session
-        .listen_for(vec![SimpleServerEvent::SchemaChange])
-        .unwrap();
+  let (mut listener, stream) = no_compression
+    .listen(vec![SimpleServerEvent::SchemaChange])
+    .expect("listen error");
 
-    thread::spawn(move || listener.start(&Compression::None).unwrap());
+  thread::spawn(move || listener.start(&Compression::None).unwrap());
 
-    let new_tables = stream
+  let new_tables = stream
         // inspects all events in a stream
         .inspect(|event| println!("inspect event {:?}", event))
         // filter by event's type: schema changes
         .filter(|event| event == &SimpleServerEvent::SchemaChange)
-        // filter by event's specific information: new node was added
+        // filter by event's specific information: new table was added
         .filter(|event| {
             match event {
                 &ServerEvent::SchemaChange(ref event) => {
@@ -42,9 +41,9 @@ fn main() {
             }
         });
 
-    println!("Start listen for server events");
+  println!("Start listen for server events");
 
-    for change in new_tables {
-        println!("server event {:?}", change);
-    }
+  for change in new_tables {
+    println!("server event {:?}", change);
+  }
 }
diff --git a/examples/simple.rs b/examples/simple.rs
deleted file mode 100644
index f30c983..0000000
--- a/examples/simple.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-
-extern crate cdrs;
-use cdrs::client::CDRS;
-use cdrs::query::QueryBuilder;
-use cdrs::authenticators::NoneAuthenticator;
-use cdrs::compression::Compression;
-use cdrs::types::IntoRustByName;
-use cdrs::transport::TransportTcp;
-
-
-/// this example is to pull employee records from emp table
-///
-/// # Examples
-///
-/// ```
-/// CREATE KEYSPACE my_namespace WITH REPLICATION = { 'class' : 'SimpleStrategy',
-/// 'replication_factor' : 1 };
-
-/// CREATE TABLE emp(
-/// emp_id int PRIMARY KEY,
-/// emp_name text,
-/// emp_city text,
-/// emp_sal varint,
-/// emp_phone varint
-/// );
-
-/// INSERT INTO emp (emp_id, emp_name, emp_city,emp_phone, emp_sal)
-/// VALUES(1,'alex', 'NJ', 9848022338, 50000)
-/// INSERT INTO emp (emp_id, emp_name, emp_city,emp_phone, emp_sal)
-/// VALUES(2,'harry', 'FLL', 9848022338, 50000)
-///
-///
-/// ```
-#[derive(Debug, Default)]
-struct Employee {
-    pub id: i64,
-    pub emp_name: String,
-    pub emp_city: String,
-    pub emp_sal: i64,
-    pub emp_phone: i64,
-}
-
-fn main() {
-
-    let addr = "127.0.0.1:9042";
-    let tcp_transport = TransportTcp::new(addr).unwrap();
-
-    // pass authenticator into CDRS' constructor
-    let client = CDRS::new(tcp_transport, NoneAuthenticator);
-
-    // start session without compression
-    let select_query = QueryBuilder::new("SELECT * FROM my_namespace.emp;").finalize();
-
-    match client.start(Compression::None) {
-        Ok(session) => {
-            let with_tracing = false;
-            let with_warnings = false;
-            let query_op = session.query(select_query, with_tracing, with_warnings);
-
-            match query_op {
-                Ok(res) => {
-                    let res_body = res.get_body();
-                    if let Some(rows) = res_body.unwrap().into_rows() {
-                        let employees: Vec<Employee> = rows.iter()
-                            .map(|row| {
-                                let mut employee = Employee { ..Default::default() };
-                                if let Ok(Some(id)) = row.get_by_name("emp_id") {
-                                    employee.id = id;
-                                }
-
-                                if let Ok(Some(emp_name)) = row.get_by_name("emp_name") {
-                                    employee.emp_name = emp_name;
-                                }
-
-                                if let Ok(Some(emp_city)) = row.get_by_name("emp_city") {
-                                    employee.emp_city = emp_city;
-                                }
-
-                                if let Ok(Some(emp_sal)) = row.get_by_name("emp_sal") {
-                                    employee.emp_sal = emp_sal;
-                                }
-
-                                if let Ok(Some(emp_phone)) = row.get_by_name("emp_phone") {
-                                    employee.emp_phone = emp_phone;
-                                }
-
-                                employee
-                            })
-                            .collect();
-                        println!("Employees {:?}", employees);
-                    }
-                }
-                Err(err) => println!("{:?}", err),
-            }
-        }
-        Err(err) => println!("{:?}", err),
-    }
-
-}
diff --git a/examples/simple_with_auth.rs b/examples/simple_with_auth.rs
deleted file mode 100644
index bede9ff..0000000
--- a/examples/simple_with_auth.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-extern crate cdrs;
-use cdrs::client::CDRS;
-use cdrs::query::QueryBuilder;
-use cdrs::authenticators::PasswordAuthenticator;
-use cdrs::compression::Compression;
-use cdrs::transport::TransportTcp;
-
-fn main() {
-
-    let authenticator = PasswordAuthenticator::new("user", "pass");
-    let addr = "127.0.0.1:9042";
-    let tcp_transport = TransportTcp::new(addr).unwrap();
-
-    // pass authenticator into CDRS' constructor
-    let client = CDRS::new(tcp_transport, authenticator);
-
-    // start session without compression
-    let select_query = QueryBuilder::new("SELECT * FROM my_namespace.emp;").finalize();
-
-    match client.start(Compression::None) {
-        Ok(session) => {
-            let with_tracing = false;
-            let with_warnings = false;
-            let query_op = session.query(select_query, with_tracing, with_warnings);
-
-            match query_op {
-
-                Ok(res) => {
-                    println!("Result frame: {:?},\nparsed body: {:?}",
-                             res,
-                             res.get_body())
-                }
-                Err(err) => println!("{:?}", err),
-            }
-
-        }
-        Err(err) => println!("{:?}", err),
-    }
-
-
-}
diff --git a/src/client.rs b/src/client.rs
deleted file mode 100644
index e85e310..0000000
--- a/src/client.rs
+++ /dev/null
@@ -1,364 +0,0 @@
-//! The modules which contains CDRS Cassandra client.
-use std::net;
-use std::io;
-use std::cell::RefCell;
-use std::collections::HashMap;
-use query::{Query, QueryBatch, QueryParams};
-use frame::{Flag, Frame, Opcode};
-use frame::frame_response::ResponseBody;
-use IntoBytes;
-use frame::parser::parse_frame;
-use types::*;
-use frame::events::SimpleServerEvent;
-
-use compression::Compression;
-use authenticators::Authenticator;
-use error;
-use transport::CDRSTransport;
-
-use events::{new_listener, EventStream, Listener};
-
-/// CDRS driver structure that provides a basic functionality to work with DB including
-/// establishing new connection, getting supported options, preparing and executing CQL
-/// queries, using compression and other.
-#[derive(Eq, PartialEq, Ord, PartialOrd)]
-pub struct CDRS<T: Authenticator, X: CDRSTransport> {
-    compressor: Compression,
-    authenticator: T,
-    transport: X,
-}
-
-/// Map of options supported by Cassandra server.
-pub type CassandraOptions = HashMap<String, Vec<String>>;
-
-impl<'a, T: Authenticator + 'a, X: CDRSTransport + 'a> CDRS<T, X> {
-    /// The method creates new instance of CDRS driver. At this step an instance doesn't
-    /// connected to DB Server. To create new instance two parameters are needed to be
-    /// provided - `addr` is IP address of DB Server, `authenticator` is a selected authenticator
-    /// that is supported by particular DB Server. There are few authenticators already
-    /// provided by this trait.
-    pub fn new(transport: X, authenticator: T) -> CDRS<T, X> {
-        CDRS { compressor: Compression::None,
-               authenticator: authenticator,
-               transport: transport, }
-    }
-
-    /// The method makes an Option request to DB Server. As a response the server returns
-    /// a map of supported options.
-    pub fn get_options(&mut self) -> error::Result<CassandraOptions> {
-        let options_frame = Frame::new_req_options().into_cbytes();
-
-        try!(self.transport.write(options_frame.as_slice()));
-
-        parse_frame(&mut self.transport, &self.compressor).map(|frame| match frame.get_body() {
-            Ok(ResponseBody::Supported(ref supported_body)) => supported_body.data.clone(),
-            _ => unreachable!(),
-        })
-    }
-
-    /// The method establishes connection to the server which address was provided on previous
-    /// step. To create connection it's required to provide a compression method from a list
-    /// of supported ones. In 4-th version of Cassandra protocol lz4 (`Compression::Lz4`)
-    /// and snappy (`Compression::Snappy`) are supported. There is also one special compression
-    /// method provided by CRDR driver, it's `Compression::None` that tells drivers that it
-    /// should work without compression. If compression is provided then incomming frames
-    /// will be decompressed automatically.
-    pub fn start(mut self, compressor: Compression) -> error::Result<Session<T, X>> {
-        self.compressor = compressor;
-        let startup_frame = Frame::new_req_startup(compressor.as_str()).into_cbytes();
-
-        try!(self.transport.write(startup_frame.as_slice()));
-        let start_response = try!(parse_frame(&mut self.transport, &compressor));
-
-        if start_response.opcode == Opcode::Ready {
-            return Ok(Session::start(self));
-        }
-
-        if start_response.opcode == Opcode::Authenticate {
-            let body = start_response.get_body()?;
-            let authenticator =
-                body.get_authenticator().expect(
-                    "Cassandra Server did communicate that it needed password
-                authentication but the  auth schema was missing in the body response",
-                );
-
-            // This creates a new scope; avoiding a clone
-            // and we check whether
-            // 1. any authenticators has been passed in by client and if not send error back
-            // 2. authenticator is provided by the client and `auth_scheme` presented by
-            //      the server and client are same if not send error back
-            // 3. if it falls through it means the preliminary conditions are true
-
-            let auth_check =
-                self.authenticator.get_cassandra_name()
-                    .ok_or(error::Error::General("No authenticator was provided".to_string()))
-                    .map(|auth| {
-                             if authenticator != auth {
-                                 let io_err = io::Error::new(
-                            io::ErrorKind::NotFound,
-                            format!(
-                                "Unsupported type of authenticator. {:?} got,
-                             but {} is supported.",
-                                authenticator, authenticator
-                            ),
-                        );
-                                 return Err(error::Error::Io(io_err));
-                             }
-                             Ok(())
-                         });
-
-            if let Err(err) = auth_check {
-                return Err(err);
-            }
-
-            let auth_token_bytes = self.authenticator.get_auth_token().into_cbytes();
-            try!(self.transport.write(Frame::new_req_auth_response(auth_token_bytes).into_cbytes()
-                                                                          .as_slice()));
-            try!(parse_frame(&mut self.transport, &compressor));
-
-            return Ok(Session::start(self));
-        }
-
-        unimplemented!();
-    }
-
-    fn drop_connection(&mut self) -> error::Result<()> {
-        self.transport.close(net::Shutdown::Both)
-            .map_err(|err| error::Error::Io(err))
-    }
-}
-
-/// The object that provides functionality for communication with Cassandra server.
-pub struct Session<T: Authenticator, X: CDRSTransport>(RefCell<InternalSession<T, X>>);
-
-impl <T: Authenticator, X: CDRSTransport> Session<T, X> {
-     /// Creates new session basing on CDRS instance.
-    pub fn start(cdrs: CDRS<T, X>) -> Session<T, X> {
-        Session(RefCell::new(InternalSession::start(cdrs)))
-    }
-
-    /// The method overrides a compression method of current session
-    pub fn compressor(&self, compressor: Compression) -> &Self {
-        self.0.borrow_mut().compressor(compressor);
-        self
-    }
-
-    /// Manually ends current session.
-    /// Apart of that session will be ended automatically when the instance is dropped.
-    pub fn end(&self) {
-        self.0.borrow_mut().end();
-    }
-
-    /// The method returns `true` if underlying connection is still alive, and `false` otherwise.
-    pub fn is_connected(&self) -> bool {
-        self.0.borrow().is_connected()
-    }
-
-    /// The method makes a request to DB Server to prepare provided query.
-    pub fn prepare(&self,
-                   query: String,
-                   with_tracing: bool,
-                   with_warnings: bool)
-                   -> error::Result<Frame> {
-        self.0.borrow_mut().prepare(query, with_tracing, with_warnings)
-    }
-
-    /// The method makes a request to DB Server to execute a query with provided id
-    /// using provided query parameters. `id` is an ID of a query which Server
-    /// returns back to a driver as a response to `prepare` request.
-    pub fn execute(&self,
-                   id: &CBytesShort,
-                   query_parameters: QueryParams,
-                   with_tracing: bool,
-                   with_warnings: bool)
-                   -> error::Result<Frame> {
-        self.0.borrow_mut().execute(id, query_parameters, with_tracing, with_warnings)
-    }
-
-    /// The method makes a request to DB Server to execute a query provided in `query` argument.
-    /// you can build the query with QueryBuilder
-    /// ```
-    /// use cdrs::query::QueryBuilder;
-    /// use cdrs::compression::Compression;
-    /// use cdrs::consistency::Consistency;
-    ///
-    ///   let select_query = QueryBuilder::new("select * from emp").finalize();
-    /// ```
-    pub fn query(&self,
-                 query: Query,
-                 with_tracing: bool,
-                 with_warnings: bool)
-                 -> error::Result<Frame> {
-        self.0.borrow_mut().query(query, with_tracing, with_warnings)
-    }
-
-    pub fn batch(&self,
-                 batch_query: QueryBatch,
-                 with_tracing: bool,
-                 with_warnings: bool)
-                 -> error::Result<Frame> {
-        self.0.borrow_mut().batch(batch_query, with_tracing, with_warnings)
-    }
-
-    /// It consumes CDRS
-    pub fn listen_for<'a>(self,
-                          events: Vec<SimpleServerEvent>)
-                          -> error::Result<(Listener<X>, EventStream)> {
-        self.0.into_inner().listen_for(events)
-    }
-}
-
-/// The object that provides functionality for communication with Cassandra server.
-struct InternalSession<T: Authenticator, X: CDRSTransport> {
-    started: bool,
-    cdrs: CDRS<T, X>,
-    compressor: Compression,
-}
-
-impl<T: Authenticator, X: CDRSTransport> InternalSession<T, X> {
-    /// Creates new session basing on CDRS instance.
-    pub fn start(cdrs: CDRS<T, X>) -> InternalSession<T, X> {
-        let compressor = cdrs.compressor.clone();
-        InternalSession { cdrs: cdrs,
-                  started: true,
-                  compressor: compressor, }
-    }
-
-    /// The method overrides a compression method of current session
-    pub fn compressor(&mut self, compressor: Compression) -> &mut Self {
-        self.compressor = compressor;
-        self
-    }
-
-    /// Manually ends current session.
-    /// Apart of that session will be ended automatically when the instance is dropped.
-    pub fn end(&mut self) {
-        if self.started {
-            self.started = false;
-            match self.cdrs.drop_connection() {
-                Ok(_) => (),
-                Err(err) => {
-                    println!("Error occured during dropping CDRS {:?}", err);
-                }
-            }
-        }
-    }
-
-    /// The method returns `true` if underlying connection is still alive, and `false` otherwise.
-    pub fn is_connected(&self) -> bool {
-        self.cdrs.transport.is_alive()
-    }
-
-    /// The method makes a request to DB Server to prepare provided query.
-    pub fn prepare(&mut self,
-                   query: String,
-                   with_tracing: bool,
-                   with_warnings: bool)
-                   -> error::Result<Frame> {
-        let mut flags = vec![];
-        if with_tracing {
-            flags.push(Flag::Tracing);
-        }
-        if with_warnings {
-            flags.push(Flag::Warning);
-        }
-
-        let options_frame = Frame::new_req_prepare(query, flags).into_cbytes();
-
-        try!(self.cdrs.transport.write(options_frame.as_slice()));
-
-        parse_frame(&mut self.cdrs.transport, &self.compressor)
-    }
-
-    /// The method makes a request to DB Server to execute a query with provided id
-    /// using provided query parameters. `id` is an ID of a query which Server
-    /// returns back to a driver as a response to `prepare` request.
-    pub fn execute(&mut self,
-                   id: &CBytesShort,
-                   query_parameters: QueryParams,
-                   with_tracing: bool,
-                   with_warnings: bool)
-                   -> error::Result<Frame> {
-        let mut flags = vec![];
-        if with_tracing {
-            flags.push(Flag::Tracing);
-        }
-        if with_warnings {
-            flags.push(Flag::Warning);
-        }
-        let options_frame = Frame::new_req_execute(id, query_parameters, flags).into_cbytes();
-
-        (self.cdrs.transport.write(options_frame.as_slice()))?;
-        parse_frame(&mut self.cdrs.transport, &self.compressor)
-    }
-
-    /// The method makes a request to DB Server to execute a query provided in `query` argument.
-    /// you can build the query with QueryBuilder
-    /// ```
-    /// use cdrs::query::QueryBuilder;
-    /// use cdrs::compression::Compression;
-    /// use cdrs::consistency::Consistency;
-    ///
-    ///   let select_query = QueryBuilder::new("select * from emp").finalize();
-    /// ```
-    pub fn query(&mut self,
-                 query: Query,
-                 with_tracing: bool,
-                 with_warnings: bool)
-                 -> error::Result<Frame> {
-        let mut flags = vec![];
-
-        if with_tracing {
-            flags.push(Flag::Tracing);
-        }
-
-        if with_warnings {
-            flags.push(Flag::Warning);
-        }
-
-        let query_frame = Frame::new_req_query(
-            query.query,
-            query.consistency,
-            query.values,
-            query.with_names,
-            query.page_size,
-            query.paging_state,
-            query.serial_consistency,
-            query.timestamp,
-            flags,
-        ).into_cbytes();
-        try!(self.cdrs.transport.write(query_frame.as_slice()));
-        parse_frame(&mut self.cdrs.transport, &self.compressor)
-    }
-
-    pub fn batch(&mut self,
-                 batch_query: QueryBatch,
-                 with_tracing: bool,
-                 with_warnings: bool)
-                 -> error::Result<Frame> {
-        let mut flags = vec![];
-
-        if with_tracing {
-            flags.push(Flag::Tracing);
-        }
-
-        if with_warnings {
-            flags.push(Flag::Warning);
-        }
-
-        let query_frame = Frame::new_req_batch(batch_query, flags).into_cbytes();
-
-        try!(self.cdrs.transport.write(query_frame.as_slice()));
-        parse_frame(&mut self.cdrs.transport, &self.compressor)
-    }
-
-    /// It consumes CDRS
-    pub fn listen_for<'a>(mut self,
-                          events: Vec<SimpleServerEvent>)
-                          -> error::Result<(Listener<X>, EventStream)> {
-        let query_frame = Frame::new_req_register(events).into_cbytes();
-        try!(self.cdrs.transport.write(query_frame.as_slice()));
-        try!(parse_frame(&mut self.cdrs.transport, &self.compressor));
-        Ok(new_listener(self.cdrs.transport))
-    }
-}
diff --git a/src/cluster.rs b/src/cluster.rs
deleted file mode 100644
index e4909b5..0000000
--- a/src/cluster.rs
+++ /dev/null
@@ -1,159 +0,0 @@
-//! This modules contains an implementation of [r2d2](https://github.com/sfackler/r2d2)
-//! functionality of connection pools. To get more details about creating r2d2 pools
-//! please refer to original documentation.
-use std::iter::Iterator;
-use query::QueryBuilder;
-use client::{Session, CDRS};
-use error::{Error as CError, Result as CResult};
-use authenticators::Authenticator;
-use compression::Compression;
-use r2d2;
-use transport::CDRSTransport;
-use rand;
-use std::sync::atomic::{AtomicUsize, Ordering};
-
-/// Load balancing strategy
-#[derive(PartialEq)]
-pub enum LoadBalancingStrategy {
-    /// Round Robin balancing strategy
-    RoundRobin,
-    /// Random balancing strategy
-    Random,
-}
-
-impl LoadBalancingStrategy {
-    /// Returns next value for selected load balancing strategy
-    pub fn next<'a, N>(&'a self, nodes: &'a Vec<N>, i: usize) -> Option<&N> {
-        match *self {
-            LoadBalancingStrategy::Random => nodes.get(self.rnd_idx((0, Some(nodes.len())))),
-            LoadBalancingStrategy::RoundRobin => {
-                let mut cycle = nodes.iter().cycle().skip(i);
-                cycle.next()
-            }
-        }
-    }
-
-    /// Returns random number from a range
-    fn rnd_idx(&self, bounds: (usize, Option<usize>)) -> usize {
-        let min = bounds.0;
-        let max = bounds.1.unwrap_or(u8::max_value() as usize);
-        let rnd = rand::random::<usize>();
-        rnd % (max - min) + min
-    }
-}
-
-/// Load balancer
-///
-/// #Example
-///
-/// ```no_run
-/// use cdrs::cluster::{LoadBalancingStrategy, LoadBalancer};
-/// use cdrs::transport::TransportTcp;
-/// let transports = vec![TransportTcp::new("127.0.0.1:9042"), TransportTcp::new("127.0.0.1:9042")];
-/// let load_balancer = LoadBalancer::new(transports, LoadBalancingStrategy::RoundRobin);
-/// let node = load_balancer.next().unwrap();
-/// ```
-pub struct LoadBalancer<T> {
-    strategy: LoadBalancingStrategy,
-    nodes: Vec<T>,
-    i: AtomicUsize,
-}
-
-impl<T> LoadBalancer<T> {
-    /// Factory function which creates new `LoadBalancer` with provided strategy.
-    pub fn new(nodes: Vec<T>, strategy: LoadBalancingStrategy) -> LoadBalancer<T> {
-        LoadBalancer { nodes: nodes,
-                       strategy: strategy,
-                       i: AtomicUsize::new(0), }
-    }
-
-    /// Returns next node basing on provided strategy.
-    pub fn next(&self) -> Option<&T> {
-        let next = self.strategy.next(&self.nodes, self.i.load(Ordering::Relaxed) as usize);
-        if self.strategy == LoadBalancingStrategy::RoundRobin {
-            self.i.fetch_add(1, Ordering::Relaxed);
-            // prevent overflow
-            let i = self.i.load(Ordering::Relaxed);
-            match i.checked_rem(self.nodes.len() as usize) {
-                Some(rem) => self.i.store(rem, Ordering::Relaxed),
-                None => return None,
-            }
-        }
-        next
-    }
-}
-
-/// [r2d2](https://github.com/sfackler/r2d2) `ManageConnection`.
-pub struct ClusterConnectionManager<T, X> {
-    load_balancer: LoadBalancer<X>,
-    authenticator: T,
-    compression: Compression,
-}
-
-impl<T, X> ClusterConnectionManager<T, X>
-    where T: Authenticator + Send + Sync + 'static
-{
-    /// Creates a new instance of `ConnectionManager`.
-    /// It requires transport, authenticator and compression as inputs.
-    pub fn new(load_balancer: LoadBalancer<X>,
-               authenticator: T,
-               compression: Compression)
-               -> ClusterConnectionManager<T, X> {
-        ClusterConnectionManager { load_balancer: load_balancer,
-                                   authenticator: authenticator,
-                                   compression: compression, }
-    }
-}
-
-impl<T: Authenticator + Send + Sync + 'static,
-     X: CDRSTransport + Send + Sync + 'static> r2d2::ManageConnection
-    for ClusterConnectionManager<T, X> {
-    type Connection = Session<T, X>;
-    type Error = CError;
-
-    fn connect(&self) -> Result<Self::Connection, Self::Error> {
-        let transport_res: CResult<X> = self.load_balancer.next()
-                                            .ok_or_else(|| "Cannot get next node".into())
-                                            .and_then(|x| x.try_clone().map_err(|e| e.into()));
-        let transport = try!(transport_res);
-        let compression = self.compression;
-        let cdrs = CDRS::new(transport, self.authenticator.clone());
-
-        cdrs.start(compression)
-    }
-
-    fn is_valid(&self, connection: &mut Self::Connection) -> Result<(), Self::Error> {
-        let query = QueryBuilder::new("SELECT * FROM system.peers;").finalize();
-
-        connection.query(query, false, false).map(|_| ())
-    }
-
-    fn has_broken(&self, _connection: &mut Self::Connection) -> bool {
-        false
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn round_robin() {
-        let nodes = vec!["a", "b", "c"];
-        let nodes_c = nodes.clone();
-        let load_balancer = LoadBalancer::new(nodes, LoadBalancingStrategy::RoundRobin);
-        for i in 0..10 {
-            assert_eq!(&nodes_c[i % 3], load_balancer.next().unwrap());
-        }
-    }
-
-    #[test]
-    fn lb_random() {
-        let nodes = vec!["a", "b", "c", "d", "e", "f", "g"];
-        let load_balancer = LoadBalancer::new(nodes, LoadBalancingStrategy::Random);
-        for _ in 0..100 {
-            let s = load_balancer.next();
-            assert!(s.is_some());
-        }
-    }
-}
diff --git a/src/cluster/cluster.rs b/src/cluster/cluster.rs
new file mode 100644
index 0000000..faba7ae
--- /dev/null
+++ b/src/cluster/cluster.rs
@@ -0,0 +1,86 @@
+use error;
+
+use authenticators::Authenticator;
+use transport::TransportTcp;
+use cluster::session::Session;
+use load_balancing::LoadBalancingStrategy;
+
+#[cfg(feature = "ssl")]
+use transport::TransportTls;
+#[cfg(feature = "ssl")]
+use openssl::ssl::SslConnector;
+
+pub struct Cluster<A> {
+  nodes_addrs: Vec<&'static str>,
+  authenticator: A,
+}
+
+impl<'a, A: Authenticator + Sized> Cluster<A> {
+  pub fn new(nodes_addrs: Vec<&'static str>, authenticator: A) -> Cluster<A> {
+    Cluster {
+      nodes_addrs,
+      authenticator,
+    }
+  }
+
+  pub fn connect<LB>(&self, lb: LB) -> error::Result<Session<LB, A>>
+  where
+    LB: LoadBalancingStrategy<TransportTcp> + Sized,
+  {
+    Session::new(&self.nodes_addrs, lb, self.authenticator.clone())
+  }
+
+  pub fn connect_snappy<LB>(&self, lb: LB) -> error::Result<Session<LB, A>>
+  where
+    LB: LoadBalancingStrategy<TransportTcp> + Sized,
+    A: Authenticator + 'a + Sized,
+  {
+    Session::new_snappy(&self.nodes_addrs, lb, self.authenticator.clone())
+  }
+
+  pub fn connect_lz4<LB>(&self, lb: LB) -> error::Result<Session<LB, A>>
+  where
+    LB: LoadBalancingStrategy<TransportTcp> + Sized,
+  {
+    Session::new_lz4(&self.nodes_addrs, lb, self.authenticator.clone())
+  }
+
+  #[cfg(feature = "ssl")]
+  pub fn connect_ssl<LB>(
+    &self,
+    lb: LB,
+    authenticator: A,
+    ssl_connector: &SslConnector,
+  ) -> error::Result<Session<LB, A>>
+  where
+    LB: LoadBalancingStrategy<TransportTls> + Sized,
+  {
+    Session::new_ssl(&self.nodes_addrs, lb, authenticator, ssl_connector)
+  }
+
+  #[cfg(feature = "ssl")]
+  pub fn connect_snappy_ssl<LB>(
+    &self,
+    lb: LB,
+    authenticator: A,
+    ssl_connector: &SslConnector,
+  ) -> error::Result<Session<LB, A>>
+  where
+    LB: LoadBalancingStrategy<TransportTls> + Sized,
+  {
+    Session::new_snappy_ssl(&self.nodes_addrs, lb, authenticator, ssl_connector)
+  }
+
+  #[cfg(feature = "ssl")]
+  pub fn connect_lz4_ssl<LB>(
+    &self,
+    lb: LB,
+    authenticator: A,
+    ssl_connector: &SslConnector,
+  ) -> error::Result<Session<LB, A>>
+  where
+    LB: LoadBalancingStrategy<TransportTls> + Sized,
+  {
+    Session::new_lz4_ssl(&self.nodes_addrs, lb, authenticator, ssl_connector)
+  }
+}
diff --git a/src/cluster/mod.rs b/src/cluster/mod.rs
new file mode 100644
index 0000000..64f5f48
--- /dev/null
+++ b/src/cluster/mod.rs
@@ -0,0 +1,28 @@
+mod cluster;
+mod pager;
+mod session;
+
+pub use cluster::cluster::Cluster;
+pub use cluster::session::Session;
+pub use cluster::pager::{QueryPager, SessionPager};
+
+use transport::CDRSTransport;
+use compression::Compression;
+use query::{BatchExecutor, ExecExecutor, PrepareExecutor, QueryExecutor};
+
+pub trait GetTransport<'a, T: CDRSTransport + 'a> {
+  fn get_transport(&mut self) -> Option<&mut T>;
+}
+
+pub trait GetCompressor<'a> {
+  fn get_compressor(&self) -> Compression;
+}
+
+pub trait CDRSSession<'a, T: CDRSTransport + 'a>
+  : GetCompressor<'a>
+  + GetTransport<'a, T>
+  + QueryExecutor<'a, T>
+  + PrepareExecutor<'a, T>
+  + ExecExecutor<'a, T>
+  + BatchExecutor<'a, T> {
+}
diff --git a/src/cluster/pager.rs b/src/cluster/pager.rs
new file mode 100644
index 0000000..b9999a9
--- /dev/null
+++ b/src/cluster/pager.rs
@@ -0,0 +1,110 @@
+use std::marker::PhantomData;
+
+use error;
+use frame::frame_result::{RowsMetadata, RowsMetadataFlag};
+use cluster::CDRSSession;
+use query::{PreparedQuery, QueryParamsBuilder};
+use types::rows::Row;
+use types::CBytes;
+use transport::CDRSTransport;
+
+pub struct SessionPager<'a, S: CDRSSession<'a, T> + 'a, T: CDRSTransport + 'a> {
+  page_size: i32,
+  session: &'a mut S,
+  transport_type: PhantomData<&'a T>,
+}
+
+impl<'a, 'b: 'a, S: CDRSSession<'a, T>, T: CDRSTransport + 'a> SessionPager<'a, S, T> {
+  pub fn new(session: &'b mut S, page_size: i32) -> SessionPager<'a, S, T> {
+    SessionPager { session,
+                   page_size,
+                   transport_type: PhantomData, }
+  }
+
+  pub fn query<Q>(&'a mut self, query: Q) -> QueryPager<'a, Q, SessionPager<'a, S, T>>
+    where Q: ToString
+  {
+    QueryPager { pager: self,
+                 paging_state: None,
+                 has_more_pages: None,
+                 query, }
+  }
+
+  pub fn exec(&'a mut self, query: &'a PreparedQuery) -> ExecPager<'a, SessionPager<'a, S, T>> {
+    ExecPager { pager: self,
+                paging_state: None,
+                has_more_pages: None,
+                query, }
+  }
+}
+
+pub struct QueryPager<'a, Q: ToString, P: 'a> {
+  pager: &'a mut P,
+  paging_state: Option<CBytes>,
+  has_more_pages: Option<bool>,
+  query: Q,
+}
+
+impl<'a, Q: ToString, T: CDRSTransport + 'a, S: CDRSSession<'a, T>>
+  QueryPager<'a, Q, SessionPager<'a, S, T>> {
+  pub fn next(&mut self) -> error::Result<Vec<Row>> {
+    let mut params = QueryParamsBuilder::new().page_size(self.pager.page_size);
+    if self.paging_state.is_some() {
+      params = params.paging_state(self.paging_state.clone().unwrap());
+    }
+
+    let body = self.pager
+                   .session
+                   .query_with_params(self.query.to_string(), params.finalize())
+                   .and_then(|frame| frame.get_body())?;
+
+    let metadata_res: error::Result<RowsMetadata> =
+      body.as_rows_metadata()
+          .ok_or("Pager query should yield a vector of rows".into());
+    let metadata = metadata_res?;
+
+    self.has_more_pages = Some(RowsMetadataFlag::has_has_more_pages(metadata.flags.clone()));
+    self.paging_state = metadata.paging_state.clone();
+    body.into_rows()
+        .ok_or("Pager query should yield a vector of rows".into())
+  }
+
+  pub fn has_more(&self) -> bool {
+    self.has_more_pages.unwrap_or(false)
+  }
+}
+
+pub struct ExecPager<'a, P: 'a> {
+  pager: &'a mut P,
+  paging_state: Option<CBytes>,
+  has_more_pages: Option<bool>,
+  query: &'a PreparedQuery,
+}
+
+impl<'a, T: CDRSTransport + 'a, S: CDRSSession<'a, T>> ExecPager<'a, SessionPager<'a, S, T>> {
+  pub fn next(&mut self) -> error::Result<Vec<Row>> {
+    let mut params = QueryParamsBuilder::new().page_size(self.pager.page_size);
+    if self.paging_state.is_some() {
+      params = params.paging_state(self.paging_state.clone().unwrap());
+    }
+
+    let body = self.pager
+                   .session
+                   .exec_with_params(self.query, params.finalize())
+                   .and_then(|frame| frame.get_body())?;
+
+    let metadata_res: error::Result<RowsMetadata> =
+      body.as_rows_metadata()
+          .ok_or("Pager query should yield a vector of rows".into());
+    let metadata = metadata_res?;
+
+    self.has_more_pages = Some(RowsMetadataFlag::has_has_more_pages(metadata.flags.clone()));
+    self.paging_state = metadata.paging_state.clone();
+    body.into_rows()
+        .ok_or("Pager query should yield a vector of rows".into())
+  }
+
+  pub fn has_more(&self) -> bool {
+    self.has_more_pages.unwrap_or(false)
+  }
+}
diff --git a/src/cluster/session.rs b/src/cluster/session.rs
new file mode 100644
index 0000000..dd0cc01
--- /dev/null
+++ b/src/cluster/session.rs
@@ -0,0 +1,345 @@
+use std::io;
+use std::io::Write;
+
+use error;
+use transport::{CDRSTransport, TransportTcp};
+use load_balancing::LoadBalancingStrategy;
+use cluster::{CDRSSession, GetCompressor, GetTransport, SessionPager};
+
+use authenticators::Authenticator;
+use compression::Compression;
+use frame::{Frame, IntoBytes, Opcode};
+use frame::parser::parse_frame;
+use query::{BatchExecutor, ExecExecutor, PrepareExecutor, QueryExecutor};
+use events::{new_listener, EventStream, Listener};
+use frame::events::SimpleServerEvent;
+
+#[cfg(feature = "ssl")]
+use transport::TransportTls;
+#[cfg(feature = "ssl")]
+use openssl::ssl::SslConnector;
+
+
+pub struct Session<LB, A> {
+  load_balancing: LB,
+  #[allow(dead_code)] authenticator: A,
+  pub compression: Compression,
+}
+
+impl<'a, LB, A> GetCompressor<'a> for Session<LB, A> {
+  fn get_compressor(&self) -> Compression {
+    self.compression.clone()
+  }
+}
+
+impl<'a, LB: Sized, A: Authenticator + 'a + Sized> Session<LB, A> {
+  pub fn paged<T: CDRSTransport>(
+    &'a mut self,
+    page_size: i32,
+  ) -> SessionPager<'a, Session<LB, A>, T>
+  where
+    Session<LB, A>: CDRSSession<'a, T>,
+  {
+    return SessionPager::new(self, page_size);
+  }
+
+  fn startup<'b, T: CDRSTransport>(
+    transport: &'b mut T,
+    session_authenticator: &'b A,
+  ) -> error::Result<()> {
+    let ref mut compression = Compression::None;
+    let startup_frame = Frame::new_req_startup(compression.as_str()).into_cbytes();
+
+    try!(transport.write(startup_frame.as_slice()));
+    let start_response = try!(parse_frame(transport, compression));
+
+    if start_response.opcode == Opcode::Ready {
+      return Ok(());
+    }
+
+    if start_response.opcode == Opcode::Authenticate {
+      let body = start_response.get_body()?;
+      let authenticator = body.get_authenticator().expect(
+        "Cassandra Server did communicate that it needed password
+                authentication but the auth schema was missing in the body response",
+      );
+
+      // This creates a new scope; avoiding a clone
+      // and we check whether
+      // 1. any authenticators has been passed in by client and if not send error back
+      // 2. authenticator is provided by the client and `auth_scheme` presented by
+      //      the server and client are same if not send error back
+      // 3. if it falls through it means the preliminary conditions are true
+
+      let auth_check = session_authenticator
+        .get_cassandra_name()
+        .ok_or(error::Error::General(
+          "No authenticator was provided".to_string(),
+        ))
+        .map(|auth| {
+          if authenticator != auth {
+            let io_err = io::Error::new(
+              io::ErrorKind::NotFound,
+              format!(
+                "Unsupported type of authenticator. {:?} got,
+                             but {} is supported.",
+                authenticator,
+                auth
+              ),
+            );
+            return Err(error::Error::Io(io_err));
+          }
+          Ok(())
+        });
+
+      if let Err(err) = auth_check {
+        return Err(err);
+      }
+
+      let auth_token_bytes = session_authenticator.get_auth_token().into_cbytes();
+      try!(
+        transport.write(
+          Frame::new_req_auth_response(auth_token_bytes)
+            .into_cbytes()
+            .as_slice()
+        )
+      );
+      try!(parse_frame(transport, compression));
+
+      return Ok(());
+    }
+
+    unimplemented!();
+  }
+}
+
+impl<
+  'a,
+  T: CDRSTransport + 'a,
+  LB: LoadBalancingStrategy<T> + Sized,
+  A: Authenticator + Sized,
+> GetTransport<'a, T> for Session<LB, A> {
+  fn get_transport(&mut self) -> Option<&mut T> {
+    self.load_balancing.next()
+  }
+}
+
+impl<
+  'a,
+  T: CDRSTransport + 'a,
+  LB: LoadBalancingStrategy<T> + Sized,
+  A: Authenticator + Sized,
+> QueryExecutor<'a, T> for Session<LB, A> {
+}
+
+impl<
+  'a,
+  T: CDRSTransport + 'a,
+  LB: LoadBalancingStrategy<T> + Sized,
+  A: Authenticator + Sized,
+> PrepareExecutor<'a, T> for Session<LB, A> {
+}
+
+impl<
+  'a,
+  T: CDRSTransport + 'a,
+  LB: LoadBalancingStrategy<T> + Sized,
+  A: Authenticator + Sized,
+> ExecExecutor<'a, T> for Session<LB, A> {
+}
+
+impl<
+  'a,
+  T: CDRSTransport + 'a,
+  LB: LoadBalancingStrategy<T> + Sized,
+  A: Authenticator + Sized,
+> BatchExecutor<'a, T> for Session<LB, A> {
+}
+
+impl<
+  'a,
+  T: CDRSTransport + 'a,
+  LB: LoadBalancingStrategy<T> + Sized,
+  A: Authenticator + Sized,
+> CDRSSession<'a, T> for Session<LB, A> {
+}
+
+impl<'a, LB: LoadBalancingStrategy<TransportTcp> + Sized, A: Authenticator + 'a + Sized>
+  Session<LB, A> {
+  pub fn new(
+    addrs: &Vec<&str>,
+    mut load_balancing: LB,
+    authenticator: A,
+  ) -> error::Result<Session<LB, A>> {
+    let mut nodes: Vec<TransportTcp> = Vec::with_capacity(addrs.len());
+
+    for addr in addrs {
+      let mut transport = TransportTcp::new(&addr)?;
+      Self::startup(&mut transport, &authenticator)?;
+      nodes.push(transport);
+    }
+
+    load_balancing.init(nodes);
+
+    Ok(Session {
+      load_balancing,
+      authenticator,
+      compression: Compression::None,
+    })
+  }
+
+  pub fn new_snappy(
+    addrs: &Vec<&str>,
+    mut load_balancing: LB,
+    authenticator: A,
+  ) -> error::Result<Session<LB, A>> {
+    let mut nodes: Vec<TransportTcp> = Vec::with_capacity(addrs.len());
+
+    for addr in addrs {
+      let mut transport = TransportTcp::new(&addr)?;
+      Self::startup(&mut transport, &authenticator)?;
+      nodes.push(transport);
+    }
+
+    load_balancing.init(nodes);
+
+    Ok(Session {
+      load_balancing,
+      authenticator,
+      compression: Compression::Snappy,
+    })
+  }
+
+  pub fn new_lz4(
+    addrs: &Vec<&str>,
+    mut load_balancing: LB,
+    authenticator: A,
+  ) -> error::Result<Session<LB, A>> {
+    let mut nodes: Vec<TransportTcp> = Vec::with_capacity(addrs.len());
+
+    for addr in addrs {
+      let mut transport = TransportTcp::new(&addr)?;
+      Self::startup(&mut transport, &authenticator)?;
+      nodes.push(transport);
+    }
+
+    load_balancing.init(nodes);
+
+    Ok(Session {
+      load_balancing,
+      authenticator,
+      compression: Compression::Lz4,
+    })
+  }
+
+  pub fn listen(
+    &mut self,
+    events: Vec<SimpleServerEvent>,
+  ) -> error::Result<(Listener<TransportTcp>, EventStream)> {
+    let authenticator = self.authenticator.clone();
+    let compression = self.get_compressor();
+    let transport = self
+      .get_transport()
+      .ok_or("Cannot connect to a cluster - no nodes provided")?;
+    let mut transport = transport.try_clone()?;
+    Self::startup(&mut transport, &authenticator)?;
+
+    let query_frame = Frame::new_req_register(events).into_cbytes();
+    try!(transport.write(query_frame.as_slice()));
+    println!("send register");
+    try!(parse_frame(&mut transport, &compression));
+    println!("receive response");
+    Ok(new_listener(transport))
+  }
+}
+
+#[cfg(feature = "ssl")]
+impl<'a, LB: LoadBalancingStrategy<TransportTls> + Sized, A: Authenticator + 'a + Sized>
+  Session<LB, A> {
+  pub fn new_ssl(
+    addrs: &Vec<&str>,
+    mut load_balancing: LB,
+    authenticator: A,
+    ssl_connector: &SslConnector,
+  ) -> error::Result<Session<LB, A>> {
+    let mut nodes: Vec<TransportTls> = Vec::with_capacity(addrs.len());
+
+    for addr in addrs {
+      let mut transport = TransportTls::new(&addr, ssl_connector)?;
+      Self::startup(&mut transport, &authenticator)?;
+      nodes.push(transport);
+    }
+
+    load_balancing.init(nodes);
+
+    Ok(Session {
+      load_balancing,
+      authenticator,
+      compression: Compression::None,
+    })
+  }
+
+  pub fn new_snappy_ssl(
+    addrs: &Vec<&str>,
+    mut load_balancing: LB,
+    authenticator: A,
+    ssl_connector: &SslConnector,
+  ) -> error::Result<Session<LB, A>> {
+    let mut nodes: Vec<TransportTls> = Vec::with_capacity(addrs.len());
+
+    for addr in addrs {
+      let mut transport = TransportTls::new(&addr, ssl_connector)?;
+      Self::startup(&mut transport, &authenticator)?;
+      nodes.push(transport);
+    }
+
+    load_balancing.init(nodes);
+
+    Ok(Session {
+      load_balancing,
+      authenticator,
+      compression: Compression::Snappy,
+    })
+  }
+
+  pub fn new_lz4_ssl(
+    addrs: &Vec<&str>,
+    mut load_balancing: LB,
+    authenticator: A,
+    ssl_connector: &SslConnector,
+  ) -> error::Result<Session<LB, A>> {
+    let mut nodes: Vec<TransportTls> = Vec::with_capacity(addrs.len());
+
+    for addr in addrs {
+      let mut transport = TransportTls::new(&addr, ssl_connector)?;
+      Self::startup(&mut transport, &authenticator)?;
+      nodes.push(transport);
+    }
+
+    load_balancing.init(nodes);
+
+    Ok(Session {
+      load_balancing,
+      authenticator,
+      compression: Compression::Lz4,
+    })
+  }
+
+  pub fn listen_ssl(
+    &mut self,
+    events: Vec<SimpleServerEvent>,
+  ) -> error::Result<(Listener<TransportTls>, EventStream)> {
+    let authenticator = self.authenticator.clone();
+    let compression = self.get_compressor();
+    let transport = self
+      .get_transport()
+      .ok_or("Cannot connect to a cluster - no nodes provided")?;
+    let mut transport = transport.try_clone()?;
+    Self::startup(&mut transport, &authenticator)?;
+
+    let query_frame = Frame::new_req_register(events).into_cbytes();
+    try!(transport.write(query_frame.as_slice()));
+    try!(parse_frame(&mut transport, &compression));
+    Ok(new_listener(transport))
+  }
+}
diff --git a/src/compression.rs b/src/compression.rs
index 8bd8e5e..296705a 100644
--- a/src/compression.rs
+++ b/src/compression.rs
@@ -8,28 +8,20 @@
 //!by the server, messages can be compressed (including the response to the STARTUP
 //!request).
 //!
-//!CDRS provides generic trait [`Compressor`][compressor].
-//!Enum [`Compression`][compression] contains implementation
-//!for `Compressor`.
-//!
 //!```no_run
-//!use cdrs::client::CDRS;
-//!use cdrs::query::QueryBuilder;
+//!use cdrs::cluster::Cluster;
 //!use cdrs::authenticators::NoneAuthenticator;
-//!use cdrs::compression::Compression;
-//!use cdrs::transport::TransportTcp;
-//!
-//!let addr = "127.0.0.1:9042";
-//!let tcp_transport = TransportTcp::new(addr).unwrap();
+//!use cdrs::load_balancing::RoundRobin;
 //!
-//!// pass authenticator into CDRS' constructor
-//!let client = CDRS::new(tcp_transport, NoneAuthenticator);
-//!let session = client.start(Compression::None);
-//!//let session = client.start(Compression::Lz4)
-//!//let session = client.start(Compression::Snappy)
+//!const _ADDR: &'static str = "127.0.0.1:9042";
+//!let cluster = Cluster::new(vec![_ADDR], NoneAuthenticator {});
+//!let mut no_compression = cluster.connect(RoundRobin::new())
+//!                                .expect("No compression connection error");
+//!let mut lz4_compression = cluster.connect_lz4(RoundRobin::new())
+//!                                 .expect("LZ4 compression connection error");
+//!let mut snappy_compression = cluster.connect_snappy(RoundRobin::new())
+//!                                  .expect("Snappy compression connection error");
 //!```
-//![compression]:enum.Compression.html
-//![compressor]:trait.Compressor.html
 
 use std::convert::From;
 use std::error::Error;
diff --git a/src/connection_manager.rs b/src/connection_manager.rs
deleted file mode 100644
index 3b68d5f..0000000
--- a/src/connection_manager.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-//! This modules contains an implementation of [r2d2](https://github.com/sfackler/r2d2)
-//! functionality of connection pools. To get more details about creating r2d2 pools
-//! please refer to original documentation.
-use client::{Session, CDRS};
-use error::Error as CError;
-use authenticators::Authenticator;
-use compression::Compression;
-use r2d2;
-use transport::CDRSTransport;
-
-/// [r2d2](https://github.com/sfackler/r2d2) `ManageConnection`.
-pub struct ConnectionManager<T, X> {
-    transport: X,
-    authenticator: T,
-    compression: Compression,
-}
-
-impl<T: Authenticator + Send + Sync + 'static, X: CDRSTransport + Send + Sync + 'static>
-    ConnectionManager<T, X> {
-    /// Creates a new instance of `ConnectionManager`.
-    /// It requires transport, authenticator and compression as inputs.
-    pub fn new(transport: X,
-               authenticator: T,
-               compression: Compression)
-               -> ConnectionManager<T, X> {
-        ConnectionManager { transport: transport,
-                            authenticator: authenticator,
-                            compression: compression, }
-    }
-}
-
-impl<T: Authenticator + Send + Sync + 'static,
-     X: CDRSTransport + Send + Sync + 'static> r2d2::ManageConnection for ConnectionManager<T, X> {
-    type Connection = Session<T, X>;
-    type Error = CError;
-
-    fn connect(&self) -> Result<Self::Connection, Self::Error> {
-        let transport = try!(self.transport.try_clone());
-        let compression = self.compression;
-        let cdrs = CDRS::new(transport, self.authenticator.clone());
-
-        cdrs.start(compression)
-    }
-
-    fn is_valid(&self, connection: &mut Self::Connection) -> Result<(), Self::Error> {
-        if connection.is_connected() {
-            Ok(())
-        } else {
-            Err("Connection to DB was dropped".into())
-        }
-    }
-
-    fn has_broken(&self, _connection: &mut Self::Connection) -> bool {
-        false
-    }
-}
diff --git a/src/consistency.rs b/src/consistency.rs
index 7f2c67f..e142578 100644
--- a/src/consistency.rs
+++ b/src/consistency.rs
@@ -4,7 +4,7 @@ use std::io;
 use std::convert::From;
 use std::default::Default;
 
-use {FromBytes, FromCursor, IntoBytes};
+use frame::{FromBytes, FromCursor, IntoBytes};
 use error;
 use types::*;
 
@@ -146,7 +146,7 @@ impl FromCursor for Consistency {
 #[cfg(test)]
 mod tests {
     use std::io::Cursor;
-    use {FromBytes, FromCursor, IntoBytes};
+    use frame::traits::{FromBytes, FromCursor, IntoBytes};
     use super::*;
 
     #[test]
diff --git a/src/error.rs b/src/error.rs
index b2ab581..fe4ce9c 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -3,6 +3,7 @@ use std::fmt;
 use std::io;
 use std::result;
 use std::string::FromUtf8Error;
+use std::fmt::Display;
 use frame::frame_error::CDRSError;
 use compression::CompressionError;
 use uuid::ParseError;
@@ -22,7 +23,7 @@ pub enum Error {
     UUIDParse(ParseError),
     /// General error
     General(String),
-    /// Internal error that may be raised during String::from_utf8
+    /// Internal error that may be raised during `String::from_utf8`
     FromUtf8(FromUtf8Error),
     /// Internal Compression/Decompression error
     Compression(CompressionError),
@@ -30,8 +31,8 @@ pub enum Error {
     Server(CDRSError),
 }
 
-pub fn column_is_empty_err() -> Error {
-    Error::General("Column or UDT property is empty".to_string())
+pub fn column_is_empty_err<T: Display>(column_name: T) -> Error {
+    Error::General(format!("Column or UDT property '{}' is empty", column_name))
 }
 
 impl fmt::Display for Error {
diff --git a/src/frame/events.rs b/src/frame/events.rs
index 510cbe6..c36276b 100644
--- a/src/frame/events.rs
+++ b/src/frame/events.rs
@@ -1,7 +1,7 @@
 use std::io::Cursor;
 use std::cmp::PartialEq;
 
-use FromCursor;
+use frame::traits::FromCursor;
 use error;
 use types::{CInet, CString, CStringList};
 
@@ -307,7 +307,7 @@ mod simple_server_event_test {
 mod topology_change_type_test {
     use super::*;
     use std::io::Cursor;
-    use FromCursor;
+    use frame::traits::FromCursor;
 
     #[test]
     fn from_cursor() {
@@ -335,7 +335,7 @@ mod topology_change_type_test {
 mod status_change_type_test {
     use super::*;
     use std::io::Cursor;
-    use FromCursor;
+    use frame::traits::FromCursor;
 
     #[test]
     fn from_cursor() {
@@ -363,7 +363,7 @@ mod status_change_type_test {
 mod schema_change_type_test {
     use super::*;
     use std::io::Cursor;
-    use FromCursor;
+    use frame::traits::FromCursor;
 
     #[test]
     fn from_cursor() {
@@ -396,7 +396,7 @@ mod schema_change_type_test {
 mod schema_change_target_test {
     use super::*;
     use std::io::Cursor;
-    use FromCursor;
+    use frame::traits::FromCursor;
 
     #[test]
     fn from_cursor() {
@@ -437,7 +437,7 @@ mod schema_change_target_test {
 mod server_event {
     use super::*;
     use std::io::Cursor;
-    use FromCursor;
+    use frame::traits::FromCursor;
 
     #[test]
     fn topology_change_new_node() {
diff --git a/src/frame/frame_auth_challenge.rs b/src/frame/frame_auth_challenge.rs
index 6aa42ac..61f857b 100644
--- a/src/frame/frame_auth_challenge.rs
+++ b/src/frame/frame_auth_challenge.rs
@@ -1,6 +1,6 @@
 use std::io::Cursor;
 
-use FromCursor;
+use frame::FromCursor;
 use error;
 use types::CBytes;
 
@@ -18,9 +18,9 @@ impl FromCursor for BodyResAuthChallenge {
 
 #[cfg(test)]
 mod tests {
-    use super::*;
-    use FromCursor;
     use std::io::Cursor;
+    use super::*;
+    use frame::traits::FromCursor;
 
     #[test]
     fn body_res_auth_challenge_from_cursor() {
diff --git a/src/frame/frame_auth_response.rs b/src/frame/frame_auth_response.rs
index 678a207..41643c6 100644
--- a/src/frame/frame_auth_response.rs
+++ b/src/frame/frame_auth_response.rs
@@ -1,7 +1,6 @@
 use rand;
 
 use types::CBytes;
-use IntoBytes;
 use frame::*;
 
 #[derive(Debug)]
@@ -47,7 +46,7 @@ impl Frame {
 mod tests {
     use super::*;
     use types::CBytes;
-    use IntoBytes;
+    use frame::traits::IntoBytes;
 
     #[test]
     fn body_req_auth_response() {
diff --git a/src/frame/frame_auth_success.rs b/src/frame/frame_auth_success.rs
index f0bd833..2a5ebe0 100644
--- a/src/frame/frame_auth_success.rs
+++ b/src/frame/frame_auth_success.rs
@@ -1,6 +1,6 @@
 use std::io::Cursor;
 
-use FromCursor;
+use frame::FromCursor;
 use error;
 
 /// `BodyReqAuthSuccess` is a frame that represents a successfull authentication response.
@@ -15,9 +15,9 @@ impl FromCursor for BodyReqAuthSuccess {
 
 #[cfg(test)]
 mod tests {
-    use super::*;
-    use FromCursor;
     use std::io::Cursor;
+    use super::*;
+    use frame::traits::FromCursor;
 
     #[test]
     fn test_name() {
diff --git a/src/frame/frame_authenticate.rs b/src/frame/frame_authenticate.rs
index 3e7a05a..4eb00d4 100644
--- a/src/frame/frame_authenticate.rs
+++ b/src/frame/frame_authenticate.rs
@@ -1,6 +1,6 @@
 use std::io::Cursor;
 
-use FromCursor;
+use frame::FromCursor;
 use error;
 use types::CString;
 
@@ -20,7 +20,7 @@ impl FromCursor for BodyResAuthenticate {
 mod tests {
     use super::*;
     use std::io::Cursor;
-    use FromCursor;
+    use frame::traits::FromCursor;
 
     #[test]
     fn body_res_authenticate() {
diff --git a/src/frame/frame_batch.rs b/src/frame/frame_batch.rs
index 5ac7a0c..56a5c59 100644
--- a/src/frame/frame_batch.rs
+++ b/src/frame/frame_batch.rs
@@ -1,10 +1,9 @@
 use rand;
-use {AsByte, FromSingleByte, IntoBytes};
 use frame::*;
-use frame::frame_query::QueryFlags;
+use query::QueryFlags;
 use types::*;
-use types::value::Value;
 use consistency::Consistency;
+use query::QueryValues;
 
 /// `BodyResReady`
 #[derive(Debug, Clone)]
@@ -13,7 +12,7 @@ pub struct BodyReqBatch {
     pub queries: Vec<BatchQuery>,
     pub consistency: Consistency,
     /// **IMPORTANT NOTE:** with names flag does not work and should not be used.
-    /// https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L409
+    /// https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L413
     pub query_flags: Vec<QueryFlags>,
     pub serial_consistency: Option<Consistency>,
     pub timestamp: Option<i64>,
@@ -99,7 +98,7 @@ pub struct BatchQuery {
     /// to implement. This will be fixed in a future version of the native
     /// protocol. See https://issues.apache.org/jira/browse/CASSANDRA-10246 for
     /// more details
-    pub values: Vec<(Option<CString>, Value)>,
+    pub values: QueryValues,
 }
 
 /// It contains either an id of prepared query or CQL string.
@@ -131,15 +130,7 @@ impl IntoBytes for BatchQuery {
 
         bytes.extend_from_slice(to_short(self.values.len() as i16).as_slice());
 
-        bytes = self.values.iter().fold(bytes, |mut _bytes, v| {
-            if let Some(ref name) = v.0 {
-                _bytes.extend_from_slice(name.into_cbytes().as_slice());
-            }
-
-            _bytes.extend_from_slice(v.1.into_cbytes().as_slice());
-
-            _bytes
-        });
+        bytes.extend_from_slice(self.values.into_cbytes().as_slice());
 
         bytes
     }
diff --git a/src/frame/frame_error.rs b/src/frame/frame_error.rs
index a449a9b..fe6acaf 100644
--- a/src/frame/frame_error.rs
+++ b/src/frame/frame_error.rs
@@ -8,7 +8,7 @@ use std::result;
 use error;
 use consistency::Consistency;
 use types::*;
-use FromCursor;
+use frame::traits::FromCursor;
 use frame::Frame;
 
 /// CDRS specific `Result` which contains a [`Frame`] in case of `Ok` and `CDRSError` if `Err`.
diff --git a/src/frame/frame_event.rs b/src/frame/frame_event.rs
index 57d91d5..7f6e088 100644
--- a/src/frame/frame_event.rs
+++ b/src/frame/frame_event.rs
@@ -1,6 +1,6 @@
 use std::io::Cursor;
 
-use FromCursor;
+use frame::FromCursor;
 use error;
 use frame::events::ServerEvent;
 
@@ -21,7 +21,7 @@ impl FromCursor for BodyResEvent {
 mod tests {
     use super::*;
     use std::io::Cursor;
-    use FromCursor;
+    use frame::traits::FromCursor;
     use frame::events::*;
 
     #[test]
diff --git a/src/frame/frame_execute.rs b/src/frame/frame_execute.rs
index b2cd3d6..366df12 100644
--- a/src/frame/frame_execute.rs
+++ b/src/frame/frame_execute.rs
@@ -1,8 +1,7 @@
 use rand;
 use types::*;
 use frame::*;
-use IntoBytes;
-use frame::frame_query::ParamsReqQuery;
+use query::QueryParams;
 
 /// The structure that represents a body of a frame of type `execute`.
 #[derive(Debug)]
@@ -10,12 +9,13 @@ pub struct BodyReqExecute<'a> {
     /// Id of prepared query
     id: &'a CBytesShort,
     /// Query paramaters which have the same meaning as one for `query`
-    query_parameters: ParamsReqQuery,
+    /// TODO: clarify if it is QueryParams or its shortened variant
+    query_parameters: QueryParams,
 }
 
 impl<'a> BodyReqExecute<'a> {
     /// The method which creates new instance of `BodyReqExecute`
-    pub fn new(id: &CBytesShort, query_parameters: ParamsReqQuery) -> BodyReqExecute {
+    pub fn new(id: &CBytesShort, query_parameters: QueryParams) -> BodyReqExecute {
         BodyReqExecute { id: id,
                          query_parameters: query_parameters, }
     }
@@ -33,7 +33,7 @@ impl<'a> IntoBytes for BodyReqExecute<'a> {
 impl Frame {
     /// **Note:** This function should be used internally for building query request frames.
     pub fn new_req_execute(id: &CBytesShort,
-                           query_parameters: ParamsReqQuery,
+                           query_parameters: QueryParams,
                            flags: Vec<Flag>)
                            -> Frame {
         let version = Version::Request;
diff --git a/src/frame/frame_options.rs b/src/frame/frame_options.rs
index 20aff0e..9b08587 100644
--- a/src/frame/frame_options.rs
+++ b/src/frame/frame_options.rs
@@ -1,5 +1,4 @@
 use rand;
-use IntoBytes;
 use frame::*;
 
 /// The structure which represents a body of a frame of type `options`.
diff --git a/src/frame/frame_prepare.rs b/src/frame/frame_prepare.rs
index 0928da8..14a1c38 100644
--- a/src/frame/frame_prepare.rs
+++ b/src/frame/frame_prepare.rs
@@ -1,7 +1,6 @@
 use rand;
 use types::*;
 use frame::*;
-use IntoBytes;
 
 /// Struct that represents a body of a frame of type `prepare`
 #[derive(Debug)]
diff --git a/src/frame/frame_query.rs b/src/frame/frame_query.rs
index e968bf8..2a0e5ef 100644
--- a/src/frame/frame_query.rs
+++ b/src/frame/frame_query.rs
@@ -3,9 +3,8 @@
 use rand;
 use frame::*;
 use consistency::Consistency;
-use {AsByte, IntoBytes};
 use types::*;
-use types::value::*;
+use query::{Query, QueryFlags, QueryParams, QueryValues};
 
 /// Structure which represents body of Query request
 #[derive(Debug)]
@@ -13,14 +12,14 @@ pub struct BodyReqQuery {
     /// Query string.
     pub query: CStringLong,
     /// Query parameters.
-    pub query_params: ParamsReqQuery,
+    pub query_params: QueryParams,
 }
 
 impl BodyReqQuery {
     // Fabric function that produces Query request body.
     fn new(query: String,
            consistency: Consistency,
-           values: Option<Vec<Value>>,
+           values: Option<QueryValues>,
            with_names: Option<bool>,
            page_size: Option<i32>,
            paging_state: Option<CBytes>,
@@ -38,6 +37,9 @@ impl BodyReqQuery {
         if page_size.is_some() {
             flags.push(QueryFlags::PageSize);
         }
+        if paging_state.is_some() {
+            flags.push(QueryFlags::WithPagingState);
+        }
         if serial_consistency.is_some() {
             flags.push(QueryFlags::WithSerialConsistency);
         }
@@ -46,13 +48,14 @@ impl BodyReqQuery {
         }
 
         BodyReqQuery { query: CStringLong::new(query),
-                       query_params: ParamsReqQuery { consistency: consistency,
-                                                      flags: flags,
-                                                      values: values,
-                                                      page_size: page_size,
-                                                      paging_state: paging_state,
-                                                      serial_consistency: serial_consistency,
-                                                      timestamp: timestamp, }, }
+                       query_params: QueryParams { consistency,
+                                                   flags,
+                                                   with_names,
+                                                   values,
+                                                   page_size,
+                                                   paging_state,
+                                                   serial_consistency,
+                                                   timestamp, }, }
     }
 }
 
@@ -65,232 +68,13 @@ impl IntoBytes for BodyReqQuery {
     }
 }
 
-/// Parameters of Query request.
-#[derive(Debug)]
-pub struct ParamsReqQuery {
-    /// Cassandra consistency level.
-    pub consistency: Consistency,
-    /// Array of query flags.
-    pub flags: Vec<QueryFlags>,
-    /// Array of values.
-    pub values: Option<Vec<Value>>,
-    /// Page size.
-    pub page_size: Option<i32>,
-    /// Array of bytes which represents paging state.
-    pub paging_state: Option<CBytes>,
-    /// Serial `Consistency`.
-    pub serial_consistency: Option<Consistency>,
-    /// Timestamp.
-    pub timestamp: Option<i64>,
-}
-
-impl ParamsReqQuery {
-    /// Sets values of Query request params.
-    pub fn set_values(&mut self, values: Vec<Value>) {
-        self.flags.push(QueryFlags::Value);
-        self.values = Some(values);
-    }
-
-    fn flags_as_byte(&self) -> u8 {
-        self.flags.iter().fold(0, |acc, flag| acc | flag.as_byte())
-    }
-
-    #[allow(dead_code)]
-    fn parse_query_flags(byte: u8) -> Vec<QueryFlags> {
-        let mut flags: Vec<QueryFlags> = vec![];
-
-        if QueryFlags::has_value(byte) {
-            flags.push(QueryFlags::Value);
-        }
-        if QueryFlags::has_skip_metadata(byte) {
-            flags.push(QueryFlags::SkipMetadata);
-        }
-        if QueryFlags::has_page_size(byte) {
-            flags.push(QueryFlags::PageSize);
-        }
-        if QueryFlags::has_with_paging_state(byte) {
-            flags.push(QueryFlags::WithPagingState);
-        }
-        if QueryFlags::has_with_serial_consistency(byte) {
-            flags.push(QueryFlags::WithSerialConsistency);
-        }
-        if QueryFlags::has_with_default_timestamp(byte) {
-            flags.push(QueryFlags::WithDefaultTimestamp);
-        }
-        if QueryFlags::has_with_names_for_values(byte) {
-            flags.push(QueryFlags::WithNamesForValues);
-        }
-
-        flags
-    }
-}
-
-impl IntoBytes for ParamsReqQuery {
-    fn into_cbytes(&self) -> Vec<u8> {
-        let mut v: Vec<u8> = vec![];
-
-        v.extend_from_slice(self.consistency.into_cbytes().as_slice());
-        v.push(self.flags_as_byte());
-        if QueryFlags::has_value(self.flags_as_byte()) {
-            if let Some(ref values) = self.values {
-                v.extend_from_slice(to_short(values.len() as i16).as_slice());
-                for val in values {
-                    v.extend_from_slice(val.into_cbytes().as_slice());
-                }
-            }
-        }
-        if QueryFlags::has_with_paging_state(self.flags_as_byte()) && self.paging_state.is_some() {
-            // XXX clone
-            v.extend_from_slice(self.paging_state
-                                    .clone()
-                                    // unwrap is safe as we've checked that
-                                    // self.paging_state.is_some()
-                                    .unwrap()
-                                    .into_cbytes()
-                                    .as_slice());
-        }
-        if QueryFlags::has_with_serial_consistency(self.flags_as_byte())
-           && self.serial_consistency.is_some()
-        {
-            // XXX clone
-            v.extend_from_slice(self.serial_consistency
-                                    .clone()
-                                    // unwrap is safe as we've checked that
-                                    // self.serial_consistency.is_some()
-                                    .unwrap()
-                                    .into_cbytes()
-                                    .as_slice());
-        }
-        if QueryFlags::has_with_default_timestamp(self.flags_as_byte()) && self.timestamp.is_some()
-        {
-            // unwrap is safe as we've checked that self.timestamp.is_some()
-            v.extend_from_slice(to_bigint(self.timestamp.unwrap()).as_slice());
-        }
-
-        v
-    }
-}
-
-const FLAGS_VALUE: u8 = 0x01;
-const FLAGS_SKIP_METADATA: u8 = 0x02;
-const WITH_PAGE_SIZE: u8 = 0x04;
-const WITH_PAGING_STATE: u8 = 0x08;
-const WITH_SERIAL_CONSISTENCY: u8 = 0x10;
-const WITH_DEFAULT_TIMESTAMP: u8 = 0x20;
-const WITH_NAME_FOR_VALUES: u8 = 0x40;
-
-/// Cassandra Query Flags.
-#[derive(Clone, Debug)]
-pub enum QueryFlags {
-    /// If set indicates that Query Params contains value.
-    Value,
-    /// If set indicates that Query Params does not contain metadata.
-    SkipMetadata,
-    /// If set indicates that Query Params contains page size.
-    PageSize,
-    /// If set indicates that Query Params contains paging state.
-    WithPagingState,
-    /// If set indicates that Query Params contains serial consistency.
-    WithSerialConsistency,
-    /// If set indicates that Query Params contains default timestamp.
-    WithDefaultTimestamp,
-    /// If set indicates that Query Params values are named ones.
-    WithNamesForValues,
-}
-
-impl QueryFlags {
-    #[doc(hidden)]
-    pub fn has_value(byte: u8) -> bool {
-        (byte & FLAGS_VALUE) != 0
-    }
-
-    #[doc(hidden)]
-    pub fn set_value(byte: u8) -> u8 {
-        byte | FLAGS_VALUE
-    }
-
-    #[doc(hidden)]
-    pub fn has_skip_metadata(byte: u8) -> bool {
-        (byte & FLAGS_SKIP_METADATA) != 0
-    }
-
-    #[doc(hidden)]
-    pub fn set_skip_metadata(byte: u8) -> u8 {
-        byte | FLAGS_SKIP_METADATA
-    }
-
-    #[doc(hidden)]
-    pub fn has_page_size(byte: u8) -> bool {
-        (byte & WITH_PAGE_SIZE) != 0
-    }
-
-    #[doc(hidden)]
-    pub fn set_page_size(byte: u8) -> u8 {
-        byte | WITH_PAGE_SIZE
-    }
-
-    #[doc(hidden)]
-    pub fn has_with_paging_state(byte: u8) -> bool {
-        (byte & WITH_PAGING_STATE) != 0
-    }
-
-    #[doc(hidden)]
-    pub fn set_with_paging_state(byte: u8) -> u8 {
-        byte | WITH_PAGING_STATE
-    }
-
-    #[doc(hidden)]
-    pub fn has_with_serial_consistency(byte: u8) -> bool {
-        (byte & WITH_SERIAL_CONSISTENCY) != 0
-    }
-
-    #[doc(hidden)]
-    pub fn set_with_serial_consistency(byte: u8) -> u8 {
-        byte | WITH_SERIAL_CONSISTENCY
-    }
-
-    #[doc(hidden)]
-    pub fn has_with_default_timestamp(byte: u8) -> bool {
-        (byte & WITH_DEFAULT_TIMESTAMP) != 0
-    }
-
-    #[doc(hidden)]
-    pub fn set_with_default_timestamp(byte: u8) -> u8 {
-        byte | WITH_DEFAULT_TIMESTAMP
-    }
-
-    #[doc(hidden)]
-    pub fn has_with_names_for_values(byte: u8) -> bool {
-        (byte & WITH_NAME_FOR_VALUES) != 0
-    }
-
-    #[doc(hidden)]
-    pub fn set_with_names_for_values(byte: u8) -> u8 {
-        byte | WITH_NAME_FOR_VALUES
-    }
-}
-
-impl AsByte for QueryFlags {
-    fn as_byte(&self) -> u8 {
-        match *self {
-            QueryFlags::Value => FLAGS_VALUE,
-            QueryFlags::SkipMetadata => FLAGS_SKIP_METADATA,
-            QueryFlags::PageSize => WITH_PAGE_SIZE,
-            QueryFlags::WithPagingState => WITH_PAGING_STATE,
-            QueryFlags::WithSerialConsistency => WITH_SERIAL_CONSISTENCY,
-            QueryFlags::WithDefaultTimestamp => WITH_DEFAULT_TIMESTAMP,
-            QueryFlags::WithNamesForValues => WITH_NAME_FOR_VALUES,
-        }
-    }
-}
-
 // Frame implementation related to BodyReqStartup
 
 impl Frame {
     /// **Note:** This function should be used internally for building query request frames.
     pub fn new_req_query(query: String,
                          consistency: Consistency,
-                         values: Option<Vec<Value>>,
+                         values: Option<QueryValues>,
                          with_names: Option<bool>,
                          page_size: Option<i32>,
                          paging_state: Option<CBytes>,
@@ -319,4 +103,17 @@ impl Frame {
                 tracing_id: None,
                 warnings: vec![], }
     }
+
+    /// **Note:** This function should be used internally for building query request frames.
+    pub fn new_query(query: Query, flags: Vec<Flag>) -> Frame {
+        Frame::new_req_query(query.query,
+                             query.params.consistency,
+                             query.params.values,
+                             query.params.with_names,
+                             query.params.page_size,
+                             query.params.paging_state,
+                             query.params.serial_consistency,
+                             query.params.timestamp,
+                             flags)
+    }
 }
diff --git a/src/frame/frame_ready.rs b/src/frame/frame_ready.rs
index f623f43..c955e05 100644
--- a/src/frame/frame_ready.rs
+++ b/src/frame/frame_ready.rs
@@ -1,5 +1,6 @@
 use std::convert::From;
-use IntoBytes;
+
+use frame::IntoBytes;
 
 #[derive(Debug, PartialEq, Default)]
 pub struct BodyResReady;
@@ -19,7 +20,7 @@ impl IntoBytes for BodyResReady {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use IntoBytes;
+    use frame::traits::IntoBytes;
 
     #[test]
     fn body_res_ready_new() {
diff --git a/src/frame/frame_register.rs b/src/frame/frame_register.rs
index bd8c049..3f48498 100644
--- a/src/frame/frame_register.rs
+++ b/src/frame/frame_register.rs
@@ -1,5 +1,4 @@
 use rand;
-use IntoBytes;
 use frame::*;
 use frame::events::SimpleServerEvent;
 use types::{CString, CStringList};
diff --git a/src/frame/frame_response.rs b/src/frame/frame_response.rs
index ff7609d..9e7dffa 100644
--- a/src/frame/frame_response.rs
+++ b/src/frame/frame_response.rs
@@ -1,10 +1,10 @@
 use std::io::Cursor;
 
-use FromCursor;
+use frame::FromCursor;
 use error;
 use frame::Opcode;
 use frame::frame_result::{BodyResResultPrepared, BodyResResultRows, BodyResResultSetKeyspace,
-                          BodyResResultVoid, ResResultBody};
+                          BodyResResultVoid, ResResultBody, RowsMetadata};
 use frame::frame_event::BodyResEvent;
 use frame::frame_error::CDRSError;
 use frame::frame_supported::*;
@@ -74,14 +74,19 @@ impl ResponseBody {
         }
     }
 
+    pub fn as_rows_metadata(&self) -> Option<RowsMetadata> {
+        match *self {
+            ResponseBody::Result(ref res) => res.as_rows_metadata(),
+            _ => None,
+        }
+    }
+
     pub fn as_cols(&self) -> Option<&BodyResResultRows> {
         match *self {
-            ResponseBody::Result(ref res) => {
-                match res {
-                    &ResResultBody::Rows(ref rows) => Some(rows),
-                    _ => None,
-                }
-            }
+            ResponseBody::Result(ref res) => match res {
+                &ResResultBody::Rows(ref rows) => Some(rows),
+                _ => None,
+            },
             _ => None,
         }
     }
diff --git a/src/frame/frame_result.rs b/src/frame/frame_result.rs
index f334bc2..ce53852 100644
--- a/src/frame/frame_result.rs
+++ b/src/frame/frame_result.rs
@@ -1,6 +1,6 @@
 use std::io::Cursor;
 
-use {FromBytes, FromCursor, IntoBytes};
+use frame::{FromBytes, FromCursor, IntoBytes};
 use error;
 use types::*;
 use types::rows::Row;
@@ -100,6 +100,14 @@ impl ResResultBody {
         }
     }
 
+    /// It returns `Some` rows metadata if frame result is of type rows and `None` othewise
+    pub fn as_rows_metadata(&self) -> Option<RowsMetadata> {
+        match *self {
+            ResResultBody::Rows(ref rows_body) => Some(rows_body.metadata.clone()),
+            _ => None,
+        }
+    }
+
     /// It unwraps body and returns BodyResResultPrepared which contains an exact result of
     /// PREPARE query.
     pub fn into_prepared(self) -> Option<BodyResResultPrepared> {
@@ -595,13 +603,12 @@ impl FromCursor for PreparedMetadata {
             // v4 or v5
             CInt::from_cursor(&mut cursor)?
         };
-        let pk_index_results: Vec<Option<i16>> =
-            (0..pk_count).map(|_| {
-                             cursor_next_value(&mut cursor, SHORT_LEN as u64)
+        let pk_index_results: Vec<Option<i16>> = (0..pk_count).map(|_| {
+            cursor_next_value(&mut cursor, SHORT_LEN as u64)
                     .ok()
                     .and_then(|b| try_i16_from_bytes(b.as_slice()).ok())
-                         })
-                         .collect();
+        })
+                                                              .collect();
 
         let pk_indexes: Vec<i16> = if pk_index_results.iter().any(Option::is_none) {
             return Err("pk indexes error".into());
diff --git a/src/frame/frame_startup.rs b/src/frame/frame_startup.rs
index fe3adfc..b217cda 100644
--- a/src/frame/frame_startup.rs
+++ b/src/frame/frame_startup.rs
@@ -3,7 +3,6 @@ use std::collections::HashMap;
 use rand;
 use frame::*;
 use types::to_short;
-use IntoBytes;
 
 const CQL_VERSION: &'static str = "CQL_VERSION";
 const CQL_VERSION_VAL: &'static str = "3.0.0";
diff --git a/src/frame/frame_supported.rs b/src/frame/frame_supported.rs
index aa25fb7..a093947 100644
--- a/src/frame/frame_supported.rs
+++ b/src/frame/frame_supported.rs
@@ -1,7 +1,7 @@
 use std::collections::HashMap;
 use std::io::Cursor;
 
-use FromCursor;
+use frame::FromCursor;
 use error;
 use types::{cursor_next_value, try_from_bytes, CString, CStringList, SHORT_LEN};
 
@@ -28,7 +28,7 @@ impl FromCursor for BodyResSupported {
 #[cfg(test)]
 mod tests {
     use std::io::Cursor;
-    use FromCursor;
+    use frame::traits::FromCursor;
     use super::*;
 
     #[test]
diff --git a/src/frame/mod.rs b/src/frame/mod.rs
index 65f4f06..13d3351 100644
--- a/src/frame/mod.rs
+++ b/src/frame/mod.rs
@@ -1,16 +1,10 @@
 //! `frame` module contains general Frame functionality.
 use types::to_n_bytes;
-use {AsByte, IntoBytes};
+pub use frame::traits::*;
 use frame::frame_response::ResponseBody;
 use compression::Compression;
 use uuid::Uuid;
 
-/// Number of version bytes in accordance to protocol.
-pub const VERSION_LEN: usize = 1;
-/// Number of flag bytes in accordance to protocol.
-pub const FLAG_LEN: usize = 1;
-/// Number of opcode bytes in accordance to protocol.
-pub const OPCODE_LEN: usize = 1;
 /// Number of stream bytes in accordance to protocol.
 pub const STREAM_LEN: usize = 2;
 /// Number of body length bytes in accordance to protocol.
@@ -35,6 +29,7 @@ pub mod frame_result;
 pub mod frame_startup;
 pub mod frame_supported;
 pub mod parser;
+pub mod traits;
 
 use error;
 
@@ -110,6 +105,11 @@ pub enum Version {
 }
 
 impl Version {
+    /// Number of bytes that represent Cassandra frame's version.
+    pub const BYTE_LENGTH: usize = 1;
+
+    /// It returns an actual Cassandra request frame version that CDRS can work with.
+    /// This version is based on selected feature - on of `v3`, `v4` or `v5`.
     fn request_version() -> u8 {
         if cfg!(feature = "v3") {
             0x03
@@ -122,6 +122,8 @@ impl Version {
         }
     }
 
+    /// It returns an actual Cassandra response frame version that CDRS can work with.
+    /// This version is based on selected feature - on of `v3`, `v4` or `v5`.
     fn response_version() -> u8 {
         if cfg!(feature = "v3") {
             0x83
@@ -146,11 +148,13 @@ impl AsByte for Version {
 
 impl From<Vec<u8>> for Version {
     fn from(v: Vec<u8>) -> Version {
-        if v.len() != VERSION_LEN {
+        if v.len() != Self::BYTE_LENGTH {
             error!("Unexpected Cassandra verion. Should has {} byte(-s), got {:?}",
-                   VERSION_LEN, v);
+                   Self::BYTE_LENGTH,
+                   v);
             panic!("Unexpected Cassandra verion. Should has {} byte(-s), got {:?}",
-                   VERSION_LEN, v);
+                   Self::BYTE_LENGTH,
+                   v);
         }
         let version = v[0];
         let req = Version::request_version();
@@ -181,6 +185,10 @@ pub enum Flag {
 }
 
 impl Flag {
+    /// Number of flag bytes in accordance to protocol.
+    const BYTE_LENGTH: usize = 1;
+
+    /// It returns selected flags collection.
     pub fn get_collection(flags: u8) -> Vec<Flag> {
         let mut found_flags: Vec<Flag> = vec![];
 
@@ -207,8 +215,8 @@ impl Flag {
     pub fn many_to_cbytes(flags: &Vec<Flag>) -> u8 {
         flags.iter()
              .fold(Flag::Ignore.as_byte(), |acc, f| {
-                 acc | f.as_byte()
-             })
+            acc | f.as_byte()
+        })
     }
 
     /// Indicates if flags contains `Flag::Compression`
@@ -277,6 +285,11 @@ pub enum Opcode {
     AuthSuccess,
 }
 
+impl Opcode {
+    // Number of opcode bytes in accordance to protocol.
+    pub const BYTE_LENGTH: usize = 1;
+}
+
 impl AsByte for Opcode {
     fn as_byte(&self) -> u8 {
         match self {
@@ -327,7 +340,7 @@ impl From<u8> for Opcode {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use AsByte;
+    use frame::traits::AsByte;
 
     #[test]
     #[cfg(not(feature = "v3"))]
diff --git a/src/frame/parser.rs b/src/frame/parser.rs
index 3f242a6..e2dfcc6 100644
--- a/src/frame/parser.rs
+++ b/src/frame/parser.rs
@@ -1,6 +1,6 @@
 use std::io::{Cursor, Read};
 
-use FromCursor;
+use frame::FromCursor;
 use compression::Compression;
 use frame::frame_response::ResponseBody;
 use super::*;
@@ -9,22 +9,18 @@ use types::data_serialization_types::decode_timeuuid;
 use error;
 
 pub fn parse_frame(cursor: &mut Read, compressor: &Compression) -> error::Result<Frame> {
-    let mut version_bytes = [0; VERSION_LEN];
-    let mut flag_bytes = [0; FLAG_LEN];
-    let mut opcode_bytes = [0; OPCODE_LEN];
+    let mut version_bytes = [0; Version::BYTE_LENGTH];
+    let mut flag_bytes = [0; Flag::BYTE_LENGTH];
+    let mut opcode_bytes = [0; Opcode::BYTE_LENGTH];
     let mut stream_bytes = [0; STREAM_LEN];
     let mut length_bytes = [0; LENGTH_LEN];
 
     // NOTE: order of reads matters
-    let v = try!(cursor.read(&mut version_bytes));
-    let f = try!(cursor.read(&mut flag_bytes));
-    let s = try!(cursor.read(&mut stream_bytes));
-    let o = try!(cursor.read(&mut opcode_bytes));
-    let l = try!(cursor.read(&mut length_bytes));
-
-    if v == 0 || f == 0 || s == 0 || o == 0 || l == 0 {
-        return Err(error::Error::from("Empty frame received"));
-    }
+    try!(cursor.read_exact(&mut version_bytes));
+    try!(cursor.read_exact(&mut flag_bytes));
+    try!(cursor.read_exact(&mut stream_bytes));
+    try!(cursor.read_exact(&mut opcode_bytes));
+    try!(cursor.read_exact(&mut length_bytes));
 
     let version = Version::from(version_bytes.to_vec());
     let flags = Flag::get_collection(flag_bytes[0]);
diff --git a/src/frame/traits.rs b/src/frame/traits.rs
new file mode 100644
index 0000000..835e96a
--- /dev/null
+++ b/src/frame/traits.rs
@@ -0,0 +1,55 @@
+use std::io::Cursor;
+
+use error;
+use types::rows::Row;
+use types::udt::UDT;
+use query;
+
+/// `IntoBytes` should be used to convert a structure into array of bytes.
+pub trait IntoBytes {
+  /// It should convert a struct into an array of bytes.
+  fn into_cbytes(&self) -> Vec<u8>;
+}
+
+/// `FromBytes` should be used to parse an array of bytes into a structure.
+pub trait FromBytes {
+  /// It gets and array of bytes and should return an implementor struct.
+  fn from_bytes(&[u8]) -> error::Result<Self>
+  where
+    Self: Sized;
+}
+
+/// `AsBytes` should be used to convert a value into a single byte.
+pub trait AsByte {
+  /// It should represent a struct as a single byte.
+  fn as_byte(&self) -> u8;
+}
+
+/// `FromSingleByte` should be used to convert a single byte into a value.
+/// It is opposite to `AsByte`.
+pub trait FromSingleByte {
+  /// It should convert a single byte into an implementor struct.
+  fn from_byte(u8) -> Self;
+}
+
+/// `FromCursor` should be used to get parsed structure from an `io:Cursor`
+/// wich bound to an array of bytes.
+pub trait FromCursor {
+  /// It should return an implementor from an `io::Cursor` over an array of bytes.
+  fn from_cursor(&mut Cursor<&[u8]>) -> error::Result<Self>
+  where
+    Self: Sized;
+}
+
+/// The trait that allows transformation of `Self` to CDRS query values.
+pub trait IntoQueryValues {
+  fn into_query_values(self) -> query::QueryValues;
+}
+
+pub trait TryFromRow: Sized {
+  fn try_from_row(row: Row) -> error::Result<Self>;
+}
+
+pub trait TryFromUDT: Sized {
+  fn try_from_udt(udt: UDT) -> error::Result<Self>;
+}
diff --git a/src/lib.rs b/src/lib.rs
index 5e6db0d..1759444 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -10,70 +10,19 @@ extern crate log;
 extern crate lz4_compress;
 #[cfg(feature = "ssl")]
 extern crate openssl;
-extern crate r2d2;
 extern crate rand;
 extern crate time;
 extern crate uuid;
 
-use std::io::Cursor;
-
+pub mod cluster;
 pub mod frame;
+pub mod load_balancing;
+pub mod query;
 pub mod types;
 
 pub mod authenticators;
-pub mod client;
-pub mod cluster;
 pub mod compression;
-pub mod connection_manager;
 pub mod consistency;
 pub mod error;
 pub mod events;
-pub mod query;
 pub mod transport;
-
-/// `IntoBytes` should be used to convert a structure into array of bytes.
-pub trait IntoBytes {
-    /// It should convert a struct into an array of bytes.
-    fn into_cbytes(&self) -> Vec<u8>;
-}
-
-/// `FromBytes` should be used to parse an array of bytes into a structure.
-pub trait FromBytes {
-    /// It gets and array of bytes and should return an implementor struct.
-    fn from_bytes(&[u8]) -> error::Result<Self>
-        where Self: Sized;
-}
-
-/// `AsBytes` should be used to convert a value into a single byte.
-pub trait AsByte {
-    /// It should represent a struct as a single byte.
-    fn as_byte(&self) -> u8;
-}
-
-/// `FromSingleByte` should be used to convert a single byte into a value.
-/// It is opposite to `AsByte`.
-pub trait FromSingleByte {
-    /// It should convert a single byte into an implementor struct.
-    fn from_byte(u8) -> Self;
-}
-
-/// `FromCursor` should be used to get parsed structure from an `io:Cursor`
-/// wich bound to an array of bytes.
-pub trait FromCursor {
-    /// It should return an implementor from an `io::Cursor` over an array of bytes.
-    fn from_cursor(&mut Cursor<&[u8]>) -> error::Result<Self>
-        where Self: Sized;
-}
-
-/// The trait that allows transformation of `Self` to `types::value::Value`.
-pub trait IntoCDRSValue {
-    /// It converts `Self` to `types::value::Value`.
-    fn into_cdrs_value(self) -> types::value::Value;
-}
-
-impl<T: Into<types::value::Bytes>> IntoCDRSValue for T {
-    fn into_cdrs_value(self) -> types::value::Value {
-        let bytes: types::value::Bytes = self.into();
-        bytes.into()
-    }
-}
diff --git a/src/load_balancing/mod.rs b/src/load_balancing/mod.rs
new file mode 100644
index 0000000..f99cb2e
--- /dev/null
+++ b/src/load_balancing/mod.rs
@@ -0,0 +1,10 @@
+mod random;
+mod round_robin;
+
+pub use load_balancing::random::Random;
+pub use load_balancing::round_robin::RoundRobin;
+
+pub trait LoadBalancingStrategy<N>: Sized {
+  fn init(&mut self, cluster: Vec<N>);
+  fn next(&mut self) -> Option<&mut N>;
+}
diff --git a/src/load_balancing/random.rs b/src/load_balancing/random.rs
new file mode 100644
index 0000000..a707861
--- /dev/null
+++ b/src/load_balancing/random.rs
@@ -0,0 +1,53 @@
+use rand;
+
+use super::LoadBalancingStrategy;
+
+pub struct Random<N> {
+  cluster: Vec<N>,
+}
+
+impl<N> Random<N> {
+  pub fn new() -> Self {
+    Random { cluster: vec![] }
+  }
+
+  /// Returns random number from a range
+  fn rnd_idx(bounds: (usize, usize)) -> usize {
+    let min = bounds.0;
+    let max = bounds.1;
+    let rnd = rand::random::<usize>();
+    rnd % (max - min) + min
+  }
+}
+
+impl<N> From<Vec<N>> for Random<N> {
+  fn from(cluster: Vec<N>) -> Random<N> {
+    Random { cluster }
+  }
+}
+
+impl<N> LoadBalancingStrategy<N> for Random<N> {
+  fn init(&mut self, cluster: Vec<N>) {
+    self.cluster = cluster;
+  }
+  /// Returns next random node from a cluster
+  fn next(&mut self) -> Option<&mut N> {
+    let len = self.cluster.len();
+    self.cluster.get_mut(Self::rnd_idx((0, len)))
+  }
+}
+
+#[cfg(test)]
+mod tests {
+  use super::*;
+
+  #[test]
+  fn random() {
+    let nodes = vec!["a", "b", "c", "d", "e", "f", "g"];
+    let mut load_balancer = Random::from(nodes);
+    for _ in 0..100 {
+      let s = load_balancer.next();
+      assert!(s.is_some());
+    }
+  }
+}
diff --git a/src/load_balancing/round_robin.rs b/src/load_balancing/round_robin.rs
new file mode 100644
index 0000000..08e810e
--- /dev/null
+++ b/src/load_balancing/round_robin.rs
@@ -0,0 +1,47 @@
+use super::LoadBalancingStrategy;
+
+pub struct RoundRobin<N> {
+  cluster: Vec<N>,
+  prev_idx: usize,
+}
+
+impl<N> RoundRobin<N> {
+  pub fn new() -> Self {
+    RoundRobin { prev_idx: 0,
+                 cluster: vec![], }
+  }
+}
+
+impl<N> From<Vec<N>> for RoundRobin<N> {
+  fn from(cluster: Vec<N>) -> RoundRobin<N> {
+    RoundRobin { prev_idx: 0,
+                 cluster, }
+  }
+}
+
+impl<N> LoadBalancingStrategy<N> for RoundRobin<N> {
+  fn init(&mut self, cluster: Vec<N>) {
+    self.cluster = cluster;
+  }
+
+  /// Returns next node from a cluster
+  fn next(&mut self) -> Option<&mut N> {
+    self.prev_idx = (self.prev_idx + 1) % self.cluster.len();
+    self.cluster.get_mut(self.prev_idx)
+  }
+}
+
+#[cfg(test)]
+mod tests {
+  use super::*;
+
+  #[test]
+  fn round_robin() {
+    let nodes = vec!["a", "b", "c"];
+    let nodes_c = nodes.clone();
+    let mut load_balancer = RoundRobin::from(nodes);
+    for i in 0..10 {
+      assert_eq!(&nodes_c[(i + 1) % 3], load_balancer.next().unwrap());
+    }
+  }
+}
diff --git a/src/macros.rs b/src/macros.rs
index 30d6f2e..49cd3e8 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -1,3 +1,30 @@
+#[macro_export]
+macro_rules! query_values {
+    ($($value:expr),*) => {
+        {
+            use cdrs::types::value::Value;
+            use cdrs::query::QueryValues;
+            let mut values: Vec<Value> = Vec::new();
+            $(
+                values.push($value.into());
+            )*
+            QueryValues::SimpleValues(values)
+        }
+    };
+    ($($name:expr => $value:expr),*) => {
+        {
+            use cdrs::types::value::Value;
+            use cdrs::query::QueryValues;
+            use std::collections::HashMap;
+            let mut values: HashMap<String, Value> = HashMap::new();
+            $(
+                values.insert($name.to_string(), $value.into());
+            )*
+            QueryValues::NamedValues(values)
+        }
+    };
+}
+
 macro_rules! builder_opt_field {
     ($field:ident, $field_type:ty) => {
         pub fn $field(mut self,
@@ -69,7 +96,7 @@ macro_rules! into_rust_by_name {
         impl IntoRustByName<$($into_type)+> for Row {
             fn get_by_name(&self, name: &str) -> Result<Option<$($into_type)+>> {
                 self.get_col_spec_by_name(name)
-                    .ok_or(column_is_empty_err())
+                    .ok_or(column_is_empty_err(name))
                     .and_then(|(col_spec, cbytes)| {
                         let ref col_type = col_spec.col_type;
                         as_rust_type!(col_type, cbytes, $($into_type)+)
@@ -81,7 +108,7 @@ macro_rules! into_rust_by_name {
         impl IntoRustByName<$($into_type)+> for UDT {
             fn get_by_name(&self, name: &str) -> Result<Option<$($into_type)+>> {
                 self.data.get(name)
-                .ok_or(column_is_empty_err())
+                .ok_or(column_is_empty_err(name))
                 .and_then(|v| {
                     let &(ref col_type, ref bytes) = v;
                     let converted = as_rust_type!(col_type, bytes, $($into_type)+);
@@ -98,7 +125,7 @@ macro_rules! into_rust_by_index {
             fn get_by_index(&self, index: usize) -> Result<Option<$($into_type)+>> {
                 self.data
                     .get(index)
-                    .ok_or(column_is_empty_err())
+                    .ok_or(column_is_empty_err(index))
                     .and_then(|v| {
                         let &(ref col_type, ref bytes) = v;
                         let converted = as_rust_type!(col_type, bytes, $($into_type)+);
@@ -111,7 +138,7 @@ macro_rules! into_rust_by_index {
         impl IntoRustByIndex<$($into_type)+> for Row {
             fn get_by_index(&self, index: usize) -> Result<Option<$($into_type)+>> {
                 self.get_col_spec_by_index(index)
-                    .ok_or(column_is_empty_err())
+                    .ok_or(column_is_empty_err(index))
                     .and_then(|(col_spec, cbytes)| {
                         let ref col_type = col_spec.col_type;
                         as_rust_type!(col_type, cbytes, $($into_type)+)
diff --git a/src/query.rs b/src/query.rs
deleted file mode 100644
index be081c2..0000000
--- a/src/query.rs
+++ /dev/null
@@ -1,379 +0,0 @@
-use types::*;
-use types::value::*;
-use error::{Error as CError, Result as CResult};
-use consistency::Consistency;
-use frame::frame_query::{ParamsReqQuery, QueryFlags};
-use frame::frame_batch::{BatchQuery, BatchQuerySubj, BatchType, BodyReqBatch};
-
-/// Structure that represents CQL query and parameters which will be applied during
-/// its execution
-#[derive(Debug, Default)]
-pub struct Query {
-    pub query: String,
-    // query parameters
-    pub consistency: Consistency,
-    pub values: Option<Vec<Value>>,
-    pub with_names: Option<bool>,
-    pub page_size: Option<i32>,
-    pub paging_state: Option<CBytes>,
-    pub serial_consistency: Option<Consistency>,
-    pub timestamp: Option<i64>,
-}
-
-/// `QueryBuilder` is a helper sturcture that helps to construct `Query`. `Query` itself
-/// consists of CQL query string and list of parameters.
-/// Parameters are the same as ones described in [Cassandra v4 protocol]
-/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L304)
-#[derive(Debug, Default)]
-pub struct QueryBuilder {
-    query: String,
-    consistency: Consistency,
-    values: Option<Vec<Value>>,
-    with_names: Option<bool>,
-    page_size: Option<i32>,
-    paging_state: Option<CBytes>,
-    serial_consistency: Option<Consistency>,
-    timestamp: Option<i64>,
-}
-
-impl QueryBuilder {
-    /// Factory function that takes CQL as an argument and returns new `QueryBuilder`.
-    /// Default consistency level is `One`
-    pub fn new<T: Into<String>>(query: T) -> QueryBuilder {
-        QueryBuilder { query: query.into(),
-                       ..Default::default() }
-    }
-
-    /// Sets new query consistency
-    pub fn consistency(mut self, consistency: Consistency) -> Self {
-        self.consistency = consistency;
-
-        self
-    }
-
-    /// Sets new query values
-    builder_opt_field!(values, Vec<Value>);
-
-    /// Sets new query with_names
-    builder_opt_field!(with_names, bool);
-
-    /// Sets new query pagesize
-    builder_opt_field!(page_size, i32);
-
-    /// Sets new query pagin state
-    builder_opt_field!(paging_state, CBytes);
-
-    /// Sets new query serial_consistency
-    builder_opt_field!(serial_consistency, Consistency);
-
-    /// Sets new quey timestamp
-    builder_opt_field!(timestamp, i64);
-
-    pub fn apply_query_params(mut self, params: QueryParams) -> Self {
-        self.consistency = params.consistency;
-        self.values = params.values;
-        self.page_size = params.page_size;
-        self.paging_state = params.paging_state;
-        self.serial_consistency = params.serial_consistency;
-        self.timestamp = params.timestamp;
-
-        self
-    }
-
-    /// Finalizes query building process and returns query itself
-    pub fn finalize(self) -> Query {
-        Query { query: self.query,
-                consistency: self.consistency,
-                values: self.values,
-                with_names: self.with_names,
-                page_size: self.page_size,
-                paging_state: self.paging_state,
-                serial_consistency: self.serial_consistency,
-                timestamp: self.timestamp, }
-    }
-}
-
-pub type QueryParams = ParamsReqQuery;
-
-/// Query parameters builder
-#[derive(Debug)]
-pub struct QueryParamsBuilder {
-    consistency: Consistency,
-    values: Option<Vec<Value>>,
-    with_names: bool,
-    page_size: Option<i32>,
-    paging_state: Option<CBytes>,
-    serial_consistency: Option<Consistency>,
-    timestamp: Option<i64>,
-}
-
-impl QueryParamsBuilder {
-    pub fn new(consistency: Consistency) -> QueryParamsBuilder {
-        QueryParamsBuilder { consistency: consistency,
-                             values: None,
-                             with_names: false,
-                             page_size: None,
-                             paging_state: None,
-                             serial_consistency: None,
-                             timestamp: None, }
-    }
-
-    pub fn values(mut self, v: Vec<Value>) -> Self {
-        self.values = Some(v);
-
-        self
-    }
-
-    pub fn with_names(mut self, with_names: bool) -> Self {
-        self.with_names = with_names;
-
-        self
-    }
-
-    pub fn page_size(mut self, page_size: i32) -> Self {
-        self.page_size = Some(page_size);
-
-        self
-    }
-
-    pub fn paging_state(mut self, paging_state: CBytes) -> Self {
-        self.paging_state = Some(paging_state);
-
-        self
-    }
-
-    pub fn serial_consistency(mut self, serial_consistency: Consistency) -> Self {
-        self.serial_consistency = Some(serial_consistency);
-
-        self
-    }
-
-    pub fn timestamp(mut self, timestamp: i64) -> Self {
-        self.timestamp = Some(timestamp);
-
-        self
-    }
-
-    pub fn finalize(self) -> QueryParams {
-        // query flags
-        let mut flags: Vec<QueryFlags> = vec![];
-
-        if self.values.is_some() {
-            flags.push(QueryFlags::Value);
-        }
-
-        if self.with_names {
-            flags.push(QueryFlags::WithNamesForValues);
-        }
-
-        if self.page_size.is_some() {
-            flags.push(QueryFlags::PageSize);
-        }
-
-        if self.serial_consistency.is_some() {
-            flags.push(QueryFlags::WithSerialConsistency);
-        }
-
-        if self.timestamp.is_some() {
-            flags.push(QueryFlags::WithDefaultTimestamp);
-        }
-
-        QueryParams { consistency: self.consistency,
-                      flags: flags,
-                      values: self.values,
-                      page_size: self.page_size,
-                      paging_state: self.paging_state,
-                      serial_consistency: self.serial_consistency,
-                      timestamp: self.timestamp, }
-    }
-}
-
-pub type QueryBatch = BodyReqBatch;
-
-#[derive(Debug)]
-pub struct BatchQueryBuilder {
-    batch_type: BatchType,
-    queries: Vec<BatchQuery>,
-    consistency: Consistency,
-    serial_consistency: Option<Consistency>,
-    timestamp: Option<i64>,
-}
-
-impl BatchQueryBuilder {
-    pub fn new() -> BatchQueryBuilder {
-        BatchQueryBuilder { batch_type: BatchType::Logged,
-                            queries: vec![],
-                            consistency: Consistency::One,
-                            serial_consistency: None,
-                            timestamp: None, }
-    }
-
-    pub fn batch_type(mut self, batch_type: BatchType) -> Self {
-        self.batch_type = batch_type;
-        self
-    }
-
-    /// Add a query (non-prepared one)
-    pub fn add_query<T: Into<String>>(mut self, query: T, values: Vec<BatchValue>) -> Self {
-        self.queries.push(BatchQuery { is_prepared: false,
-                               subject:
-                                   BatchQuerySubj::QueryString(CStringLong::new(query.into())),
-                               values: values, });
-        self
-    }
-
-    /// Add a query (prepared one)
-    pub fn add_query_prepared(mut self, query_id: CBytesShort, values: Vec<BatchValue>) -> Self {
-        self.queries.push(BatchQuery { is_prepared: true,
-                                       subject: BatchQuerySubj::PreparedId(query_id),
-                                       values: values, });
-        self
-    }
-
-    pub fn clear_queries(mut self) -> Self {
-        self.queries = vec![];
-        self
-    }
-
-    pub fn consistency(mut self, consistency: Consistency) -> Self {
-        self.consistency = consistency;
-        self
-    }
-
-    pub fn serial_consistency(mut self, serial_consistency: Option<Consistency>) -> Self {
-        self.serial_consistency = serial_consistency;
-        self
-    }
-
-    pub fn timestamp(mut self, timestamp: Option<i64>) -> Self {
-        self.timestamp = timestamp;
-        self
-    }
-
-    pub fn finalize(self) -> CResult<BodyReqBatch> {
-        let mut flags = vec![];
-
-        if self.serial_consistency.is_some() {
-            flags.push(QueryFlags::WithSerialConsistency);
-        }
-
-        if self.timestamp.is_some() {
-            flags.push(QueryFlags::WithDefaultTimestamp);
-        }
-
-        let with_names_for_values = self.queries.iter()
-                                        .all(|q| q.values.iter().all(|v| v.0.is_some()));
-
-        if !with_names_for_values {
-            let some_names_for_values = self.queries.iter()
-                                            .any(|q| q.values.iter().any(|v| v.0.is_some()));
-
-            if some_names_for_values {
-                return Err(CError::General(String::from("Inconsistent query values - mixed \
-                                                         with and without names values")));
-            }
-        }
-
-        if with_names_for_values {
-            flags.push(QueryFlags::WithNamesForValues);
-        }
-
-        Ok(BodyReqBatch { batch_type: self.batch_type,
-                          queries: self.queries,
-                          query_flags: flags,
-                          consistency: self.consistency,
-                          serial_consistency: self.serial_consistency,
-                          timestamp: self.timestamp, })
-    }
-}
-
-pub type BatchValue = (Option<CString>, Value);
-
-#[cfg(test)]
-mod query_builder {
-    use super::*;
-
-    #[test]
-    fn new() {
-        let _ = QueryBuilder::new("USE keyspace").finalize();
-    }
-
-    #[test]
-    fn with_parameters() {
-        let _ = QueryBuilder::new("USE keyspace").consistency(Consistency::Two)
-                                                 .values(vec![Value::new_null()])
-                                                 .with_names(true)
-                                                 .page_size(11)
-                                                 .paging_state(CBytes::new(vec![1, 2, 3, 4, 5]))
-                                                 .serial_consistency(Consistency::One)
-                                                 .timestamp(1245678)
-                                                 .finalize();
-    }
-}
-
-#[cfg(test)]
-mod query_params_builder {
-    use super::*;
-
-    #[test]
-    fn new() {
-        let _ = QueryParamsBuilder::new(Consistency::Two).finalize();
-    }
-
-    #[test]
-    fn with_parameters() {
-        let _ = QueryParamsBuilder::new(Consistency::Two).values(vec![Value::new_null()])
-                                                         .with_names(true)
-                                                         .page_size(11)
-                                                         .paging_state(CBytes::new(vec![1, 2, 3,
-                                                                                        4, 5]))
-                                                         .serial_consistency(Consistency::One)
-                                                         .timestamp(1245678)
-                                                         .finalize();
-    }
-}
-
-#[cfg(test)]
-mod batch_query_builder {
-    use super::*;
-
-    #[test]
-    fn new() {
-        assert!(BatchQueryBuilder::new().finalize().is_ok());
-    }
-
-    #[test]
-    fn newwith_defaults() {
-        let newwith_defaults = BatchQueryBuilder::new().finalize();
-        match newwith_defaults {
-            Ok(n) => {
-                assert!(n.batch_type == BatchType::Logged);
-                assert!(n.consistency == Consistency::One);
-                assert!(n.serial_consistency == None);
-                assert!(n.timestamp == None);
-                assert!(n.queries.is_empty());
-            }
-            Err(_) => assert!(false, "Error should not happen"),
-        }
-    }
-
-    #[test]
-    fn with_parameters() {
-        let q = BatchQueryBuilder::new().batch_type(BatchType::Logged)
-                                        .add_query("some query".to_string(), vec![])
-                                        .add_query_prepared(CBytesShort::new(vec![1, 2, 3]), vec![])
-                                        .consistency(Consistency::One)
-                                        .serial_consistency(Some(Consistency::Two))
-                                        .timestamp(Some(1234))
-                                        .finalize();
-        assert!(q.is_ok())
-    }
-
-    #[test]
-    fn clear_queries() {
-        let q = BatchQueryBuilder::new().add_query("some query".to_string(), vec![])
-                                        .clear_queries()
-                                        .finalize();
-        assert!(q.is_ok())
-    }
-}
diff --git a/src/query/batch_executor.rs b/src/query/batch_executor.rs
new file mode 100644
index 0000000..96c19bd
--- /dev/null
+++ b/src/query/batch_executor.rs
@@ -0,0 +1,37 @@
+use error;
+use transport::CDRSTransport;
+use cluster::{GetCompressor, GetTransport};
+use frame::{Flag, Frame};
+use frame::parser::parse_frame;
+use frame::traits::IntoBytes;
+use query::batch_query_builder::QueryBatch;
+
+pub trait BatchExecutor<'a, T: CDRSTransport + 'a>
+  : GetTransport<'a, T> + GetCompressor<'a> {
+  fn batch_with_params_tw(&mut self,
+                          batch: QueryBatch,
+                          with_tracing: bool,
+                          with_warnings: bool)
+                          -> error::Result<Frame> {
+    let mut flags = vec![];
+
+    if with_tracing {
+      flags.push(Flag::Tracing);
+    }
+
+    if with_warnings {
+      flags.push(Flag::Warning);
+    }
+
+    let query_frame = Frame::new_req_batch(batch, flags).into_cbytes();
+    let ref compression = self.get_compressor();
+    let transport = self.get_transport().ok_or("Unable to get transport")?;
+
+    try!(transport.write(query_frame.as_slice()));
+    parse_frame(transport, compression)
+  }
+
+  fn batch_with_params(&mut self, batch: QueryBatch) -> error::Result<Frame> {
+    self.batch_with_params_tw(batch, false, false)
+  }
+}
diff --git a/src/query/batch_query_builder.rs b/src/query/batch_query_builder.rs
new file mode 100644
index 0000000..fed78af
--- /dev/null
+++ b/src/query/batch_query_builder.rs
@@ -0,0 +1,102 @@
+use error::{Error as CError, Result as CResult};
+use consistency::Consistency;
+use frame::frame_batch::{BatchQuery, BatchQuerySubj, BatchType, BodyReqBatch};
+use query::{QueryFlags, QueryValues};
+use types::{CBytesShort, CStringLong};
+
+pub type QueryBatch = BodyReqBatch;
+
+#[derive(Debug)]
+pub struct BatchQueryBuilder {
+  batch_type: BatchType,
+  queries: Vec<BatchQuery>,
+  consistency: Consistency,
+  serial_consistency: Option<Consistency>,
+  timestamp: Option<i64>,
+}
+
+impl BatchQueryBuilder {
+  pub fn new() -> BatchQueryBuilder {
+    BatchQueryBuilder { batch_type: BatchType::Logged,
+                        queries: vec![],
+                        consistency: Consistency::One,
+                        serial_consistency: None,
+                        timestamp: None, }
+  }
+
+  pub fn batch_type(mut self, batch_type: BatchType) -> Self {
+    self.batch_type = batch_type;
+    self
+  }
+
+  /// Add a query (non-prepared one)
+  pub fn add_query<T: Into<String>>(mut self, query: T, values: QueryValues) -> Self {
+    self.queries
+        .push(BatchQuery { is_prepared: false,
+                           subject: BatchQuerySubj::QueryString(CStringLong::new(query.into())),
+                           values, });
+    self
+  }
+
+  /// Add a query (prepared one)
+  pub fn add_query_prepared(mut self, query_id: CBytesShort, values: QueryValues) -> Self {
+    self.queries.push(BatchQuery { is_prepared: true,
+                                   subject: BatchQuerySubj::PreparedId(query_id),
+                                   values, });
+    self
+  }
+
+  pub fn clear_queries(mut self) -> Self {
+    self.queries = vec![];
+    self
+  }
+
+  pub fn consistency(mut self, consistency: Consistency) -> Self {
+    self.consistency = consistency;
+    self
+  }
+
+  pub fn serial_consistency(mut self, serial_consistency: Option<Consistency>) -> Self {
+    self.serial_consistency = serial_consistency;
+    self
+  }
+
+  pub fn timestamp(mut self, timestamp: Option<i64>) -> Self {
+    self.timestamp = timestamp;
+    self
+  }
+
+  pub fn finalize(self) -> CResult<BodyReqBatch> {
+    let mut flags = vec![];
+
+    if self.serial_consistency.is_some() {
+      flags.push(QueryFlags::WithSerialConsistency);
+    }
+
+    if self.timestamp.is_some() {
+      flags.push(QueryFlags::WithDefaultTimestamp);
+    }
+
+    let with_names_for_values = self.queries.iter().all(|q| q.values.with_names());
+
+    if !with_names_for_values {
+      let some_names_for_values = self.queries.iter().any(|q| q.values.with_names());
+
+      if some_names_for_values {
+        return Err(CError::General(String::from("Inconsistent query values - mixed \
+                                                 with and without names values")));
+      }
+    }
+
+    if with_names_for_values {
+      flags.push(QueryFlags::WithNamesForValues);
+    }
+
+    Ok(BodyReqBatch { batch_type: self.batch_type,
+                      queries: self.queries,
+                      query_flags: flags,
+                      consistency: self.consistency,
+                      serial_consistency: self.serial_consistency,
+                      timestamp: self.timestamp, })
+  }
+}
diff --git a/src/query/exec_executor.rs b/src/query/exec_executor.rs
new file mode 100644
index 0000000..c2cc3ac
--- /dev/null
+++ b/src/query/exec_executor.rs
@@ -0,0 +1,72 @@
+use error;
+use query::{QueryParams, QueryParamsBuilder, QueryValues};
+use frame::{Flag, Frame, IntoBytes};
+use frame::parser::parse_frame;
+use types::CBytesShort;
+use cluster::{GetCompressor, GetTransport};
+use transport::CDRSTransport;
+
+pub type PreparedQuery = CBytesShort;
+
+pub trait ExecExecutor<'a, T: CDRSTransport + 'a>
+  : GetTransport<'a, T> + GetCompressor<'a> {
+  fn exec_with_params_tw(&mut self,
+                         prepared: &PreparedQuery,
+                         query_parameters: QueryParams,
+                         with_tracing: bool,
+                         with_warnings: bool)
+                         -> error::Result<Frame> {
+    let mut flags = vec![];
+    if with_tracing {
+      flags.push(Flag::Tracing);
+    }
+    if with_warnings {
+      flags.push(Flag::Warning);
+    }
+
+    let options_frame = Frame::new_req_execute(prepared, query_parameters, flags).into_cbytes();
+    let ref compression = self.get_compressor();
+    let transport = self.get_transport().ok_or("Unable to get transport")?;
+
+    (transport.write(options_frame.as_slice()))?;
+    parse_frame(transport, compression)
+  }
+
+  fn exec_with_params(&mut self,
+                      prepared: &PreparedQuery,
+                      query_parameters: QueryParams)
+                      -> error::Result<Frame> {
+    self.exec_with_params_tw(prepared, query_parameters, false, false)
+  }
+
+  fn exec_with_values_tw<V: Into<QueryValues>>(&mut self,
+                                               prepared: &PreparedQuery,
+                                               values: V,
+                                               with_tracing: bool,
+                                               with_warnings: bool)
+                                               -> error::Result<Frame> {
+    let query_params_builder = QueryParamsBuilder::new();
+    let query_params = query_params_builder.values(values.into()).finalize();
+    self.exec_with_params_tw(prepared, query_params, with_tracing, with_warnings)
+  }
+
+  fn exec_with_values<V: Into<QueryValues>>(&mut self,
+                                            prepared: &PreparedQuery,
+                                            values: V)
+                                            -> error::Result<Frame> {
+    self.exec_with_values_tw(prepared, values, false, false)
+  }
+
+  fn exec_tw(&mut self,
+             prepared: &PreparedQuery,
+             with_tracing: bool,
+             with_warnings: bool)
+             -> error::Result<Frame> {
+    let query_params = QueryParamsBuilder::new().finalize();
+    self.exec_with_params_tw(prepared, query_params, with_tracing, with_warnings)
+  }
+
+  fn exec(&'a mut self, prepared: &PreparedQuery) -> error::Result<Frame> {
+    self.exec_tw(prepared, false, false)
+  }
+}
diff --git a/src/query/mod.rs b/src/query/mod.rs
new file mode 100644
index 0000000..1a9ca59
--- /dev/null
+++ b/src/query/mod.rs
@@ -0,0 +1,21 @@
+mod batch_executor;
+mod batch_query_builder;
+mod exec_executor;
+mod prepare_executor;
+mod query_executor;
+mod query_flags;
+mod query;
+mod query_params_builder;
+mod query_values;
+mod query_params;
+
+pub use query::batch_executor::BatchExecutor;
+pub use query::batch_query_builder::{BatchQueryBuilder, QueryBatch};
+pub use query::exec_executor::ExecExecutor;
+pub use query::prepare_executor::{PrepareExecutor, PreparedQuery};
+pub use query::query_executor::QueryExecutor;
+pub use query::query_flags::QueryFlags;
+pub use query::query::Query;
+pub use query::query_params_builder::QueryParamsBuilder;
+pub use query::query_params::QueryParams;
+pub use query::query_values::QueryValues;
diff --git a/src/query/prepare_executor.rs b/src/query/prepare_executor.rs
new file mode 100644
index 0000000..a1a994a
--- /dev/null
+++ b/src/query/prepare_executor.rs
@@ -0,0 +1,41 @@
+use error;
+use frame::{Flag, Frame, IntoBytes};
+use types::CBytesShort;
+use cluster::{GetCompressor, GetTransport};
+use transport::CDRSTransport;
+use frame::parser::parse_frame;
+
+pub type PreparedQuery = CBytesShort;
+
+pub trait PrepareExecutor<'a, T: CDRSTransport + 'a>
+  : GetTransport<'a, T> + GetCompressor<'a> {
+  /// It prepares a query for execution, along with query itself
+  /// the method takes `with_tracing` and `with_warnings` flags
+  /// to get tracing information and warnings.
+  fn prepare_tw<Q: ToString>(&'a mut self,
+                             query: Q,
+                             with_tracing: bool,
+                             with_warnings: bool)
+                             -> error::Result<PreparedQuery> {
+    let mut flags = vec![];
+    if with_tracing {
+      flags.push(Flag::Tracing);
+    }
+    if with_warnings {
+      flags.push(Flag::Warning);
+    }
+
+    let options_frame = Frame::new_req_prepare(query.to_string(), flags).into_cbytes();
+    let ref compression = self.get_compressor();
+    let transport = self.get_transport().ok_or("Unable to get transport")?;
+
+    try!(transport.write(options_frame.as_slice()));
+    parse_frame(transport, compression).and_then(|response| response.get_body())
+                                       .and_then(|body| Ok(body.into_prepared().expect("").id))
+  }
+
+  /// It prepares query without additional tracing information and warnings.
+  fn prepare<Q: ToString>(&'a mut self, query: Q) -> error::Result<PreparedQuery> {
+    self.prepare_tw(query, false, false)
+  }
+}
diff --git a/src/query/query.rs b/src/query/query.rs
new file mode 100644
index 0000000..6f15de0
--- /dev/null
+++ b/src/query/query.rs
@@ -0,0 +1,9 @@
+use super::QueryParams;
+
+/// Structure that represents CQL query and parameters which will be applied during
+/// its execution
+#[derive(Debug, Default)]
+pub struct Query {
+  pub query: String,
+  pub params: QueryParams,
+}
diff --git a/src/query/query_executor.rs b/src/query/query_executor.rs
new file mode 100644
index 0000000..1e5cd87
--- /dev/null
+++ b/src/query/query_executor.rs
@@ -0,0 +1,81 @@
+use error;
+use frame::{Flag, Frame, IntoBytes};
+use query::{Query, QueryParams, QueryParamsBuilder, QueryValues};
+use cluster::{GetCompressor, GetTransport};
+use transport::CDRSTransport;
+use frame::parser::parse_frame;
+
+pub trait QueryExecutor<'a, T: CDRSTransport + 'a>
+  : GetTransport<'a, T> + GetCompressor<'a> {
+  fn query_with_params_tw<Q: ToString>(&mut self,
+                                       query: Q,
+                                       query_params: QueryParams,
+                                       with_tracing: bool,
+                                       with_warnings: bool)
+                                       -> error::Result<Frame> {
+    let query = Query { query: query.to_string(),
+                        params: query_params, };
+
+    let mut flags = vec![];
+
+    if with_tracing {
+      flags.push(Flag::Tracing);
+    }
+
+    if with_warnings {
+      flags.push(Flag::Warning);
+    }
+
+    let query_frame = Frame::new_query(query, flags).into_cbytes();
+    let ref compression = self.get_compressor();
+    let transport = self.get_transport().ok_or("Unable to get transport")?;
+    try!(transport.write(query_frame.as_slice()));
+    parse_frame(transport, compression)
+  }
+
+  /// Executes a query with default parameters:
+  /// * TDB
+  fn query<Q: ToString>(&mut self, query: Q) -> error::Result<Frame> {
+    self.query_tw(query, false, false)
+  }
+
+  /// Executes a query with ability to trace it and see warnings, and default parameters:
+  /// * TBD
+  fn query_tw<Q: ToString>(&mut self,
+                           query: Q,
+                           with_tracing: bool,
+                           with_warnings: bool)
+                           -> error::Result<Frame> {
+    let query_params = QueryParamsBuilder::new().finalize();
+    self.query_with_params_tw(query, query_params, with_tracing, with_warnings)
+  }
+
+  /// Executes a query with bounded values (either with or without names).
+  fn query_with_values<Q: ToString, V: Into<QueryValues>>(&mut self,
+                                                          query: Q,
+                                                          values: V)
+                                                          -> error::Result<Frame> {
+    self.query_with_values_tw(query, values, false, false)
+  }
+
+  /// Executes a query with bounded values (either with or without names)
+  /// and ability to see warnings, trace a request and default parameters.
+  fn query_with_values_tw<Q: ToString, V: Into<QueryValues>>(&mut self,
+                                                             query: Q,
+                                                             values: V,
+                                                             with_tracing: bool,
+                                                             with_warnings: bool)
+                                                             -> error::Result<Frame> {
+    let query_params_builder = QueryParamsBuilder::new();
+    let query_params = query_params_builder.values(values.into()).finalize();
+    self.query_with_params_tw(query, query_params, with_tracing, with_warnings)
+  }
+
+  /// Executes a query with query params without warnings and tracing.
+  fn query_with_params<Q: ToString>(&mut self,
+                                    query: Q,
+                                    query_params: QueryParams)
+                                    -> error::Result<Frame> {
+    self.query_with_params_tw(query, query_params, false, false)
+  }
+}
diff --git a/src/query/query_flags.rs b/src/query/query_flags.rs
new file mode 100644
index 0000000..943c732
--- /dev/null
+++ b/src/query/query_flags.rs
@@ -0,0 +1,255 @@
+use frame::AsByte;
+
+const FLAGS_VALUE: u8 = 0x01;
+const FLAGS_SKIP_METADATA: u8 = 0x02;
+const WITH_PAGE_SIZE: u8 = 0x04;
+const WITH_PAGING_STATE: u8 = 0x08;
+const WITH_SERIAL_CONSISTENCY: u8 = 0x10;
+const WITH_DEFAULT_TIMESTAMP: u8 = 0x20;
+const WITH_NAME_FOR_VALUES: u8 = 0x40;
+
+/// Cassandra Query Flags.
+#[derive(Clone, Debug)]
+pub enum QueryFlags {
+  /// If set indicates that Query Params contains value.
+  Value,
+  /// If set indicates that Query Params does not contain metadata.
+  SkipMetadata,
+  /// If set indicates that Query Params contains page size.
+  PageSize,
+  /// If set indicates that Query Params contains paging state.
+  WithPagingState,
+  /// If set indicates that Query Params contains serial consistency.
+  WithSerialConsistency,
+  /// If set indicates that Query Params contains default timestamp.
+  WithDefaultTimestamp,
+  /// If set indicates that Query Params values are named ones.
+  WithNamesForValues,
+}
+
+impl QueryFlags {
+  #[doc(hidden)]
+  pub fn has_value(byte: u8) -> bool {
+    (byte & FLAGS_VALUE) != 0
+  }
+
+  #[doc(hidden)]
+  pub fn set_value(byte: u8) -> u8 {
+    byte | FLAGS_VALUE
+  }
+
+  #[doc(hidden)]
+  pub fn has_skip_metadata(byte: u8) -> bool {
+    (byte & FLAGS_SKIP_METADATA) != 0
+  }
+
+  #[doc(hidden)]
+  pub fn set_skip_metadata(byte: u8) -> u8 {
+    byte | FLAGS_SKIP_METADATA
+  }
+
+  #[doc(hidden)]
+  pub fn has_page_size(byte: u8) -> bool {
+    (byte & WITH_PAGE_SIZE) != 0
+  }
+
+  #[doc(hidden)]
+  pub fn set_page_size(byte: u8) -> u8 {
+    byte | WITH_PAGE_SIZE
+  }
+
+  #[doc(hidden)]
+  pub fn has_with_paging_state(byte: u8) -> bool {
+    (byte & WITH_PAGING_STATE) != 0
+  }
+
+  #[doc(hidden)]
+  pub fn set_with_paging_state(byte: u8) -> u8 {
+    byte | WITH_PAGING_STATE
+  }
+
+  #[doc(hidden)]
+  pub fn has_with_serial_consistency(byte: u8) -> bool {
+    (byte & WITH_SERIAL_CONSISTENCY) != 0
+  }
+
+  #[doc(hidden)]
+  pub fn set_with_serial_consistency(byte: u8) -> u8 {
+    byte | WITH_SERIAL_CONSISTENCY
+  }
+
+  #[doc(hidden)]
+  pub fn has_with_default_timestamp(byte: u8) -> bool {
+    (byte & WITH_DEFAULT_TIMESTAMP) != 0
+  }
+
+  #[doc(hidden)]
+  pub fn set_with_default_timestamp(byte: u8) -> u8 {
+    byte | WITH_DEFAULT_TIMESTAMP
+  }
+
+  #[doc(hidden)]
+  pub fn has_with_names_for_values(byte: u8) -> bool {
+    (byte & WITH_NAME_FOR_VALUES) != 0
+  }
+
+  #[doc(hidden)]
+  pub fn set_with_names_for_values(byte: u8) -> u8 {
+    byte | WITH_NAME_FOR_VALUES
+  }
+}
+
+impl AsByte for QueryFlags {
+  fn as_byte(&self) -> u8 {
+    match *self {
+      QueryFlags::Value => FLAGS_VALUE,
+      QueryFlags::SkipMetadata => FLAGS_SKIP_METADATA,
+      QueryFlags::PageSize => WITH_PAGE_SIZE,
+      QueryFlags::WithPagingState => WITH_PAGING_STATE,
+      QueryFlags::WithSerialConsistency => WITH_SERIAL_CONSISTENCY,
+      QueryFlags::WithDefaultTimestamp => WITH_DEFAULT_TIMESTAMP,
+      QueryFlags::WithNamesForValues => WITH_NAME_FOR_VALUES,
+    }
+  }
+}
+
+#[cfg(test)]
+mod tests {
+  use super::*;
+
+  #[test]
+  fn has_value_test() {
+    assert!(QueryFlags::has_value(FLAGS_VALUE | 0x10),
+            "should show that the flag has value");
+    assert!(!QueryFlags::has_value(FLAGS_SKIP_METADATA),
+            "should show that the flag does NOT have value");
+  }
+
+  #[test]
+  fn set_value_test() {
+    assert_eq!(QueryFlags::set_value(0),
+               FLAGS_VALUE,
+               "should set has value flag");
+  }
+
+  #[test]
+  fn has_skip_metadata_test() {
+    assert!(QueryFlags::has_skip_metadata(FLAGS_SKIP_METADATA | 0x10),
+            "should show that the flag has skip metadata");
+    assert!(!QueryFlags::has_skip_metadata(FLAGS_VALUE),
+            "should show that the flag does NOT have skip metadata");
+  }
+
+  #[test]
+  fn set_skip_metadata_test() {
+    assert_eq!(QueryFlags::set_skip_metadata(0),
+               FLAGS_SKIP_METADATA,
+               "should set has skip metadata flag");
+  }
+
+  #[test]
+  fn has_page_size_test() {
+    assert!(QueryFlags::has_page_size(WITH_PAGE_SIZE | 0x10),
+            "should show that the flag has with page size");
+    assert!(!QueryFlags::has_page_size(FLAGS_VALUE),
+            "should show that the flag does NOT have with page size");
+  }
+
+  #[test]
+  fn set_page_size_test() {
+    assert_eq!(QueryFlags::set_page_size(0),
+               WITH_PAGE_SIZE,
+               "should set has page size flag");
+  }
+
+  #[test]
+  fn has_with_paging_state_test() {
+    assert!(QueryFlags::has_with_paging_state(WITH_PAGING_STATE | 0x10),
+            "should show that the flag has with paging state");
+    assert!(!QueryFlags::has_with_paging_state(FLAGS_VALUE),
+            "should show that the flag does NOT have with paging state");
+  }
+
+  #[test]
+  fn set_with_paging_state_test() {
+    assert_eq!(QueryFlags::set_with_paging_state(0),
+               WITH_PAGING_STATE,
+               "should set has with paging state flag");
+  }
+
+  #[test]
+  fn has_with_serial_consistency_test() {
+    assert!(QueryFlags::has_with_serial_consistency(WITH_SERIAL_CONSISTENCY | 0x11),
+            "should show that the flag has with serial consistency");
+    assert!(!QueryFlags::has_with_serial_consistency(FLAGS_VALUE),
+            "should show that the flag does NOT have with serial consistency");
+  }
+
+  #[test]
+  fn set_with_serial_consistency_test() {
+    assert_eq!(QueryFlags::set_with_serial_consistency(0),
+               WITH_SERIAL_CONSISTENCY,
+               "should set has with serial consistency flag");
+  }
+
+  #[test]
+  fn has_with_default_timestamp_test() {
+    assert!(QueryFlags::has_with_default_timestamp(WITH_DEFAULT_TIMESTAMP | 0x10),
+            "should show that the flag has with default timestamp");
+    assert!(!QueryFlags::has_with_default_timestamp(FLAGS_VALUE),
+            "should show that the flag does NOT have with default timestamp");
+  }
+
+  #[test]
+  fn set_with_default_timestamp_test() {
+    assert_eq!(QueryFlags::set_with_default_timestamp(0),
+               WITH_DEFAULT_TIMESTAMP,
+               "should set has with serial consistency flag");
+  }
+
+  #[test]
+  fn has_with_names_for_values_test() {
+    assert!(QueryFlags::has_with_names_for_values(WITH_NAME_FOR_VALUES | 0x10),
+            "should show that the flag has with name for values");
+    assert!(!QueryFlags::has_with_names_for_values(FLAGS_VALUE),
+            "should show that the flag does NOT have with name for values");
+  }
+
+  #[test]
+  fn set_with_names_for_values_test() {
+    assert_eq!(QueryFlags::set_with_names_for_values(0),
+               WITH_NAME_FOR_VALUES,
+               "should set has with name for values flag");
+  }
+
+  #[test]
+  fn as_byte_test() {
+    assert_eq!(QueryFlags::Value.as_byte(),
+               FLAGS_VALUE,
+               "should propery convert values flag");
+
+    assert_eq!(QueryFlags::SkipMetadata.as_byte(),
+               FLAGS_SKIP_METADATA,
+               "should propery convert skip metadata flag");
+
+    assert_eq!(QueryFlags::PageSize.as_byte(),
+               WITH_PAGE_SIZE,
+               "should propery convert with page size flag");
+
+    assert_eq!(QueryFlags::WithPagingState.as_byte(),
+               WITH_PAGING_STATE,
+               "should propery convert with paging state flag");
+
+    assert_eq!(QueryFlags::WithSerialConsistency.as_byte(),
+               WITH_SERIAL_CONSISTENCY,
+               "should propery convert with serial consistency flag");
+
+    assert_eq!(QueryFlags::WithDefaultTimestamp.as_byte(),
+               WITH_DEFAULT_TIMESTAMP,
+               "should propery convert with default timestamp flag");
+
+    assert_eq!(QueryFlags::WithNamesForValues.as_byte(),
+               WITH_NAME_FOR_VALUES,
+               "should propery convert with name for values flag");
+  }
+}
diff --git a/src/query/query_params.rs b/src/query/query_params.rs
new file mode 100644
index 0000000..19257ef
--- /dev/null
+++ b/src/query/query_params.rs
@@ -0,0 +1,119 @@
+use consistency::Consistency;
+use types::{to_bigint, to_int, to_short, CBytes};
+use frame::AsByte;
+use frame::IntoBytes;
+use query::query_flags::QueryFlags;
+use query::query_values::QueryValues;
+
+/// Parameters of Query for query operation.
+#[derive(Debug, Default)]
+pub struct QueryParams {
+  /// Cassandra consistency level.
+  pub consistency: Consistency,
+  /// Array of query flags.
+  pub flags: Vec<QueryFlags>,
+  /// Were values provided with names
+  pub with_names: Option<bool>,
+  /// Array of values.
+  pub values: Option<QueryValues>,
+  /// Page size.
+  pub page_size: Option<i32>,
+  /// Array of bytes which represents paging state.
+  pub paging_state: Option<CBytes>,
+  /// Serial `Consistency`.
+  pub serial_consistency: Option<Consistency>,
+  /// Timestamp.
+  pub timestamp: Option<i64>,
+}
+
+impl QueryParams {
+  /// Sets values of Query request params.
+  pub fn set_values(&mut self, values: QueryValues) {
+    self.flags.push(QueryFlags::Value);
+    self.values = Some(values);
+  }
+
+  fn flags_as_byte(&self) -> u8 {
+    self.flags.iter().fold(0, |acc, flag| acc | flag.as_byte())
+  }
+
+  #[allow(dead_code)]
+  fn parse_query_flags(byte: u8) -> Vec<QueryFlags> {
+    let mut flags: Vec<QueryFlags> = vec![];
+
+    if QueryFlags::has_value(byte) {
+      flags.push(QueryFlags::Value);
+    }
+    if QueryFlags::has_skip_metadata(byte) {
+      flags.push(QueryFlags::SkipMetadata);
+    }
+    if QueryFlags::has_page_size(byte) {
+      flags.push(QueryFlags::PageSize);
+    }
+    if QueryFlags::has_with_paging_state(byte) {
+      flags.push(QueryFlags::WithPagingState);
+    }
+    if QueryFlags::has_with_serial_consistency(byte) {
+      flags.push(QueryFlags::WithSerialConsistency);
+    }
+    if QueryFlags::has_with_default_timestamp(byte) {
+      flags.push(QueryFlags::WithDefaultTimestamp);
+    }
+    if QueryFlags::has_with_names_for_values(byte) {
+      flags.push(QueryFlags::WithNamesForValues);
+    }
+
+    flags
+  }
+}
+
+impl IntoBytes for QueryParams {
+  fn into_cbytes(&self) -> Vec<u8> {
+    let mut v: Vec<u8> = vec![];
+
+    v.extend_from_slice(self.consistency.into_cbytes().as_slice());
+    v.push(self.flags_as_byte());
+    if QueryFlags::has_value(self.flags_as_byte()) {
+      if let Some(ref values) = self.values {
+        v.extend_from_slice(to_short(values.len() as i16).as_slice());
+        v.extend_from_slice(values.into_cbytes().as_slice());
+      }
+    }
+    if QueryFlags::has_page_size(self.flags_as_byte()) && self.page_size.is_some() {
+      // XXX clone
+      v.extend_from_slice(to_int(self.page_size
+                                    .clone()
+                                    // unwrap is safe as we've checked that
+                                    // self.page_size.is_some()
+                                    .unwrap())
+                                    .as_slice());
+    }
+    if QueryFlags::has_with_paging_state(self.flags_as_byte()) && self.paging_state.is_some() {
+      // XXX clone
+      v.extend_from_slice(self.paging_state
+                                    .clone()
+                                    // unwrap is safe as we've checked that
+                                    // self.paging_state.is_some()
+                                    .unwrap()
+                                    .into_cbytes()
+                                    .as_slice());
+    }
+    if QueryFlags::has_with_serial_consistency(self.flags_as_byte())
+       && self.serial_consistency.is_some() {
+      // XXX clone
+      v.extend_from_slice(self.serial_consistency
+                                    .clone()
+                                    // unwrap is safe as we've checked that
+                                    // self.serial_consistency.is_some()
+                                    .unwrap()
+                                    .into_cbytes()
+                                    .as_slice());
+    }
+    if QueryFlags::has_with_default_timestamp(self.flags_as_byte()) && self.timestamp.is_some() {
+      // unwrap is safe as we've checked that self.timestamp.is_some()
+      v.extend_from_slice(to_bigint(self.timestamp.unwrap()).as_slice());
+    }
+
+    v
+  }
+}
diff --git a/src/query/query_params_builder.rs b/src/query/query_params_builder.rs
new file mode 100644
index 0000000..9a07eff
--- /dev/null
+++ b/src/query/query_params_builder.rs
@@ -0,0 +1,95 @@
+use consistency::Consistency;
+use types::CBytes;
+use super::{QueryFlags, QueryParams, QueryValues};
+
+#[derive(Debug, Default)]
+pub struct QueryParamsBuilder {
+  consistency: Consistency,
+  flags: Option<Vec<QueryFlags>>,
+  values: Option<QueryValues>,
+  with_names: Option<bool>,
+  page_size: Option<i32>,
+  paging_state: Option<CBytes>,
+  serial_consistency: Option<Consistency>,
+  timestamp: Option<i64>,
+}
+
+impl QueryParamsBuilder {
+  /// Factory function that returns new `QueryBuilder`.
+  /// Default consistency level is `One`
+  pub fn new() -> QueryParamsBuilder {
+    Default::default()
+  }
+
+  /// Sets new query consistency
+  pub fn consistency(mut self, consistency: Consistency) -> Self {
+    self.consistency = consistency;
+
+    self
+  }
+
+  /// Sets new flags.
+  builder_opt_field!(flags, Vec<QueryFlags>);
+
+  /// Sets new values.
+  /// Sets new query consistency
+  pub fn values(mut self, values: QueryValues) -> Self {
+    let with_names = values.with_names();
+    self.with_names = Some(with_names);
+    self.values = Some(values);
+    self.flags = self.flags.or(Some(vec![])).map(|mut flags| {
+                                                   flags.push(QueryFlags::Value);
+                                                   if with_names {
+                                                     flags.push(QueryFlags::WithNamesForValues);
+                                                   }
+                                                   flags
+                                                 });
+
+    self
+  }
+
+  /// Sets new with_names parameter value.
+  builder_opt_field!(with_names, bool);
+
+  /// Sets new values.
+  /// Sets new query consistency
+  pub fn page_size(mut self, size: i32) -> Self {
+    self.page_size = Some(size);
+    self.flags = self.flags.or(Some(vec![])).map(|mut flags| {
+                                                   flags.push(QueryFlags::PageSize);
+                                                   flags
+                                                 });
+
+    self
+  }
+
+  /// Sets new values.
+  /// Sets new query consistency
+  pub fn paging_state(mut self, state: CBytes) -> Self {
+    self.paging_state = Some(state);
+    self.flags = self.flags.or(Some(vec![])).map(|mut flags| {
+                                                   flags.push(QueryFlags::WithPagingState);
+                                                   flags
+                                                 });
+
+    self
+  }
+
+  /// Sets new serial_consistency value.
+  builder_opt_field!(serial_consistency, Consistency);
+
+  /// Sets new timestamp value.
+  builder_opt_field!(timestamp, i64);
+
+  /// Finalizes query building process and returns query itself
+  pub fn finalize(self) -> QueryParams {
+    QueryParams { consistency: self.consistency,
+                  flags: self.flags.unwrap_or(vec![]),
+                  values: self.values,
+                  with_names: self.with_names,
+                  page_size: self.page_size,
+                  paging_state: self.paging_state,
+                  serial_consistency: self.serial_consistency,
+                  timestamp: self.timestamp, }
+  }
+}
diff --git a/src/query/query_values.rs b/src/query/query_values.rs
new file mode 100644
index 0000000..470fd1e
--- /dev/null
+++ b/src/query/query_values.rs
@@ -0,0 +1,89 @@
+use std::collections::HashMap;
+use std::hash::Hash;
+
+use frame::IntoBytes;
+use types::CString;
+use types::value::Value;
+
+/// Enum that represents two types of query values:
+/// * values without name
+/// * values with names
+#[derive(Debug, Clone)]
+pub enum QueryValues {
+  SimpleValues(Vec<Value>),
+  NamedValues(HashMap<String, Value>),
+}
+
+impl QueryValues {
+  /// It returns `true` if query values is with names and `false` otherwise.
+  pub fn with_names(&self) -> bool {
+    match *self {
+      QueryValues::SimpleValues(_) => false,
+      _ => true,
+    }
+  }
+
+  /// It return number of values.
+  pub fn len(&self) -> usize {
+    match *self {
+      QueryValues::SimpleValues(ref v) => v.len(),
+      QueryValues::NamedValues(ref m) => m.len(),
+    }
+  }
+
+  fn named_value_into_bytes_fold(mut bytes: Vec<u8>, vals: (&String, &Value)) -> Vec<u8> {
+    let mut name_bytes = CString::new(vals.0.clone()).into_cbytes();
+    let mut vals_bytes = vals.1.into_cbytes();
+    bytes.append(&mut name_bytes);
+    bytes.append(&mut vals_bytes);
+    bytes
+  }
+
+  fn value_into_bytes_fold(mut bytes: Vec<u8>, val: &Value) -> Vec<u8> {
+    let mut val_bytes = val.into_cbytes();
+    bytes.append(&mut val_bytes);
+    bytes
+  }
+}
+
+impl<T: Into<Value> + Clone> From<Vec<T>> for QueryValues {
+  /// It converts values from `Vec` to query values without names `QueryValues::SimpleValues`.
+  fn from(values: Vec<T>) -> QueryValues {
+    let vals = values.iter().map(|v| v.clone().into());
+    QueryValues::SimpleValues(vals.collect())
+  }
+}
+
+impl<'a, T: Into<Value> + Clone> From<&'a [T]> for QueryValues {
+  /// It converts values from `Vec` to query values without names `QueryValues::SimpleValues`.
+  fn from(values: &'a [T]) -> QueryValues {
+    let vals = values.iter().map(|v| v.clone().into());
+    QueryValues::SimpleValues(vals.collect())
+  }
+}
+
+impl<S: ToString + Hash + Eq, V: Into<Value> + Clone> From<HashMap<S, V>> for QueryValues {
+  /// It converts values from `HashMap` to query values with names `QueryValues::NamedValues`.
+  fn from(values: HashMap<S, V>) -> QueryValues {
+    let map: HashMap<String, Value> = HashMap::with_capacity(values.len());
+    let _values = values.iter().fold(map, |mut acc, v| {
+      let name = v.0;
+      let val = v.1;
+      acc.insert(name.to_string(), val.clone().into());
+      acc
+    });
+    QueryValues::NamedValues(_values)
+  }
+}
+
+impl IntoBytes for QueryValues {
+  fn into_cbytes(&self) -> Vec<u8> {
+    let bytes: Vec<u8> = vec![];
+    match *self {
+      QueryValues::SimpleValues(ref v) => v.iter().fold(bytes, QueryValues::value_into_bytes_fold),
+      QueryValues::NamedValues(ref v) => {
+        v.iter().fold(bytes, QueryValues::named_value_into_bytes_fold)
+      }
+    }
+  }
+}
diff --git a/src/transport.rs b/src/transport.rs
index f6022df..5dace10 100644
--- a/src/transport.rs
+++ b/src/transport.rs
@@ -10,21 +10,6 @@
 //! * `TransportTls` is a transport which is used to establish SSL encrypted connection
 //!with Apache Cassandra server. **Note:** this option is available if and only if CDRS is imported
 //!with `ssl` feature.
-//!
-//! # Examples
-//!
-//!```no_run
-//!    use cdrs::transport::TransportTcp;
-//!    use cdrs::authenticators::NoneAuthenticator;
-//!    use cdrs::client::CDRS;
-//!
-//!    let addr = "127.0.0.1:9042";
-//!    let tcp_transport = TransportTcp::new(addr).unwrap();
-//!
-//!    // pass authenticator into CDRS' constructor
-//!    let client = CDRS::new(tcp_transport, NoneAuthenticator);
-//!```
-//![tTcp]:struct.TransportTcp.html
 
 use std::io;
 use std::io::{Read, Write};
@@ -77,8 +62,10 @@ impl TransportTcp {
     /// let tcp_transport = TransportTcp::new(addr).unwrap();
     /// ```
     pub fn new(addr: &str) -> io::Result<TransportTcp> {
-        TcpStream::connect(addr).map(|socket| TransportTcp { tcp: socket,
-                                                             addr: addr.to_string(), })
+        TcpStream::connect(addr).map(|socket| {
+            TransportTcp { tcp: socket,
+                           addr: addr.to_string(), }
+        })
     }
 }
 
@@ -100,9 +87,10 @@ impl Write for TransportTcp {
 
 impl CDRSTransport for TransportTcp {
     fn try_clone(&self) -> io::Result<TransportTcp> {
-        TcpStream::connect(self.addr.as_str()).map(|socket| TransportTcp { tcp: socket,
-                                                                           addr:
-                                                                               self.addr.clone(), })
+        TcpStream::connect(self.addr.as_str()).map(|socket| {
+            TransportTcp { tcp: socket,
+                           addr: self.addr.clone(), }
+        })
     }
 
     fn close(&mut self, close: net::Shutdown) -> io::Result<()> {
@@ -131,10 +119,11 @@ impl TransportTls {
     pub fn new(addr: &str, connector: &SslConnector) -> io::Result<TransportTls> {
         let a: Vec<&str> = addr.split(':').collect();
         let res = net::TcpStream::connect(addr).map(|socket| {
-            connector.connect(a[0], socket)
-                     .map(|sslsocket| TransportTls { ssl: sslsocket,
-                                                     connector: connector.clone(),
-                                                     addr: addr.to_string(), })
+            connector.connect(a[0], socket).map(|sslsocket| {
+                TransportTls { ssl: sslsocket,
+                               connector: connector.clone(),
+                               addr: addr.to_string(), }
+            })
         });
 
         res.and_then(|res| {
@@ -176,11 +165,10 @@ impl CDRSTransport for TransportTls {
 
         let res = net::TcpStream::connect(self.addr.as_str()).map(|socket| {
             self.connector.connect(ip, socket).map(|sslsocket| {
-                                                       TransportTls { ssl: sslsocket,
-                                                                      connector:
-                                                                          self.connector.clone(),
-                                                                      addr: self.addr.clone(), }
-                                                   })
+                TransportTls { ssl: sslsocket,
+                               connector: self.connector.clone(),
+                               addr: self.addr.clone(), }
+            })
         });
 
         res.and_then(|res| {
diff --git a/src/types/data_serialization_types.rs b/src/types/data_serialization_types.rs
index 502a5f3..ba90b0c 100644
--- a/src/types/data_serialization_types.rs
+++ b/src/types/data_serialization_types.rs
@@ -2,11 +2,12 @@ use std::ops::Mul;
 use std::io;
 use std::net;
 use std::string::FromUtf8Error;
+
 use uuid;
 use super::*;
 use super::blob::Blob;
 use error;
-use FromCursor;
+use frame::FromCursor;
 
 // https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L813
 
@@ -96,12 +97,10 @@ pub fn decode_float(bytes: &[u8]) -> Result<f32, io::Error> {
 pub fn decode_inet(bytes: &[u8]) -> Result<net::IpAddr, io::Error> {
     match bytes.len() {
         // v4
-        4 => {
-            Ok(net::IpAddr::V4(net::Ipv4Addr::new(bytes[0],
-                                                  bytes[1],
-                                                  bytes[2],
-                                                  bytes[3])))
-        }
+        4 => Ok(net::IpAddr::V4(net::Ipv4Addr::new(bytes[0],
+                                                   bytes[1],
+                                                   bytes[2],
+                                                   bytes[3]))),
         // v6
         16 => {
             let a = from_u16_bytes(&bytes[0..2]);
@@ -138,11 +137,9 @@ pub fn decode_list(bytes: &[u8]) -> Result<Vec<CBytes>, io::Error> {
         CInt::from_cursor(&mut cursor).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
     let mut list = Vec::with_capacity(l as usize);
     for _ in 0..l {
-        let b =
-            CBytes::from_cursor(&mut cursor).map_err(|err| {
-                                                          io::Error::new(io::ErrorKind::InvalidData,
-                                                                         err)
-                                                      })?;
+        let b = CBytes::from_cursor(&mut cursor).map_err(|err| {
+            io::Error::new(io::ErrorKind::InvalidData, err)
+        })?;
         list.push(b);
     }
     Ok(list)
@@ -157,21 +154,16 @@ pub fn decode_set(bytes: &[u8]) -> Result<Vec<CBytes>, io::Error> {
 pub fn decode_map(bytes: &[u8]) -> Result<Vec<(CBytes, CBytes)>, io::Error> {
     let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(bytes);
     let l = CInt::from_cursor(&mut cursor).map_err(|err| {
-                                                        io::Error::new(io::ErrorKind::InvalidData,
-                                                                       err)
-                                                    })?;
+        io::Error::new(io::ErrorKind::InvalidData, err)
+    })?;
     let mut map = Vec::with_capacity(l as usize);
     for _ in 0..l {
-        let n =
-            CBytes::from_cursor(&mut cursor).map_err(|err| {
-                                                          io::Error::new(io::ErrorKind::InvalidData,
-                                                                         err)
-                                                      })?;
-        let v =
-            CBytes::from_cursor(&mut cursor).map_err(|err| {
-                                                          io::Error::new(io::ErrorKind::InvalidData,
-                                                                         err)
-                                                      })?;
+        let n = CBytes::from_cursor(&mut cursor).map_err(|err| {
+            io::Error::new(io::ErrorKind::InvalidData, err)
+        })?;
+        let v = CBytes::from_cursor(&mut cursor).map_err(|err| {
+            io::Error::new(io::ErrorKind::InvalidData, err)
+        })?;
         map.push((n, v));
     }
     Ok(map)
@@ -217,8 +209,7 @@ pub fn decode_udt(bytes: &[u8], l: usize) -> Result<Vec<CBytes>, io::Error> {
             CBytes::from_cursor(&mut cursor).or_else(|err| match err {
                                                          error::Error::Io(io_err) => {
                                                              if io_err.kind()
-                                                                == io::ErrorKind::UnexpectedEof
-                                                             {
+                                                                == io::ErrorKind::UnexpectedEof {
                                                                  Ok(CBytes::new_empty())
                                                              } else {
                                                                  Err(io_err.into())
@@ -227,9 +218,8 @@ pub fn decode_udt(bytes: &[u8], l: usize) -> Result<Vec<CBytes>, io::Error> {
                                                          _ => Err(err),
                                                      })
                                             .map_err(|err| {
-                                                         io::Error::new(io::ErrorKind::InvalidData,
-                                                                        err)
-                                                     })?;
+                io::Error::new(io::ErrorKind::InvalidData, err)
+            })?;
         udt.push(v);
     }
     Ok(udt)
@@ -241,11 +231,9 @@ pub fn decode_tuple(bytes: &[u8], l: usize) -> Result<Vec<CBytes>, io::Error> {
     let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(bytes);
     let mut udt = Vec::with_capacity(l);
     for _ in 0..l {
-        let v =
-            CBytes::from_cursor(&mut cursor).map_err(|err| {
-                                                          io::Error::new(io::ErrorKind::InvalidData,
-                                                                         err)
-                                                      })?;
+        let v = CBytes::from_cursor(&mut cursor).map_err(|err| {
+            io::Error::new(io::ErrorKind::InvalidData, err)
+        })?;
         udt.push(v);
     }
     Ok(udt)
diff --git a/src/types/from_cdrs.rs b/src/types/from_cdrs.rs
new file mode 100644
index 0000000..37bc340
--- /dev/null
+++ b/src/types/from_cdrs.rs
@@ -0,0 +1,81 @@
+use std::net::IpAddr;
+use uuid::Uuid;
+use time::Timespec;
+
+use error::Result as CDRSResult;
+use types::{AsRustType, ByName, IntoRustByName};
+use types::blob::Blob;
+use types::list::List;
+use types::map::Map;
+use types::udt::UDT;
+use types::tuple::Tuple;
+
+pub trait FromCDRS {
+  fn from_cdrs<T>(cdrs_type: T) -> CDRSResult<Option<Self>>
+  where
+    Self: Sized,
+    T: AsRustType<Self> + Sized,
+  {
+    cdrs_type.as_rust_type()
+  }
+
+  fn from_cdrs_r<T>(cdrs_type: T) -> CDRSResult<Self>
+  where
+    Self: Sized,
+    T: AsRustType<Self> + Sized,
+  {
+    cdrs_type.as_r_type()
+  }
+}
+
+impl FromCDRS for Blob {}
+impl FromCDRS for String {}
+impl FromCDRS for bool {}
+impl FromCDRS for i64 {}
+impl FromCDRS for i32 {}
+impl FromCDRS for i16 {}
+impl FromCDRS for i8 {}
+impl FromCDRS for f64 {}
+impl FromCDRS for f32 {}
+impl FromCDRS for IpAddr {}
+impl FromCDRS for Uuid {}
+impl FromCDRS for List {}
+impl FromCDRS for Map {}
+impl FromCDRS for UDT {}
+impl FromCDRS for Tuple {}
+impl FromCDRS for Timespec {}
+
+pub trait FromCDRSByName {
+  fn from_cdrs_by_name<T>(cdrs_type: &T, name: &str) -> CDRSResult<Option<Self>>
+  where
+    Self: Sized,
+    T: ByName + IntoRustByName<Self> + Sized,
+  {
+    cdrs_type.by_name(name)
+  }
+
+  fn from_cdrs_r<T>(cdrs_type: &T, name: &str) -> CDRSResult<Self>
+  where
+    Self: Sized,
+    T: ByName + IntoRustByName<Self> + Sized + ::std::fmt::Debug,
+  {
+    cdrs_type.r_by_name(name)
+  }
+}
+
+impl FromCDRSByName for Blob {}
+impl FromCDRSByName for String {}
+impl FromCDRSByName for bool {}
+impl FromCDRSByName for i64 {}
+impl FromCDRSByName for i32 {}
+impl FromCDRSByName for i16 {}
+impl FromCDRSByName for i8 {}
+impl FromCDRSByName for f64 {}
+impl FromCDRSByName for f32 {}
+impl FromCDRSByName for IpAddr {}
+impl FromCDRSByName for Uuid {}
+impl FromCDRSByName for List {}
+impl FromCDRSByName for Map {}
+impl FromCDRSByName for UDT {}
+impl FromCDRSByName for Tuple {}
+impl FromCDRSByName for Timespec {}
diff --git a/src/types/mod.rs b/src/types/mod.rs
index df64371..1a1b7ce 100644
--- a/src/types/mod.rs
+++ b/src/types/mod.rs
@@ -7,7 +7,7 @@ use std::net::SocketAddr;
 use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt};
 use error::{column_is_empty_err, Error as CDRSError, Result as CDRSResult};
 use types::data_serialization_types::decode_inet;
-use {FromBytes, FromCursor, IntoBytes};
+use frame::traits::{FromBytes, FromCursor, IntoBytes};
 
 pub const LONG_STR_LEN: usize = 4;
 pub const SHORT_LEN: usize = 2;
@@ -17,6 +17,7 @@ pub const UUID_LEN: usize = 16;
 #[macro_use]
 pub mod blob;
 pub mod data_serialization_types;
+pub mod from_cdrs;
 pub mod list;
 pub mod map;
 pub mod rows;
@@ -24,26 +25,42 @@ pub mod udt;
 pub mod value;
 pub mod tuple;
 
+pub mod prelude {
+    pub use types::blob::Blob;
+    pub use types::list::List;
+    pub use types::map::Map;
+    pub use types::rows::Row;
+    pub use types::udt::UDT;
+    pub use types::tuple::Tuple;
+    pub use types::AsRustType;
+    pub use types::value::{Bytes, Value};
+    pub use frame::{TryFromRow, TryFromUDT};
+}
+
 /// Should be used to represent a single column as a Rust value.
 pub trait AsRustType<T> {
     fn as_rust_type(&self) -> CDRSResult<Option<T>>;
 
     fn as_r_type(&self) -> CDRSResult<T> {
-        self.as_rust_type().and_then(|op| op.ok_or(CDRSError::from("Value is null or non-set")))
+        self.as_rust_type()
+            .and_then(|op| op.ok_or(CDRSError::from("Value is null or non-set")))
     }
 }
 
 pub trait AsRust {
     fn as_rust<R>(&self) -> CDRSResult<Option<R>>
-        where Self: AsRustType<R>
+    where
+        Self: AsRustType<R>,
     {
         self.as_rust_type()
     }
 
     fn as_r_rust<T>(&self) -> CDRSResult<T>
-        where Self: AsRustType<T>
+    where
+        Self: AsRustType<T>,
     {
-        self.as_rust().and_then(|op| op.ok_or("Value is null or non-set".into()))
+        self.as_rust()
+            .and_then(|op| op.ok_or("Value is null or non-set".into()))
     }
 }
 
@@ -52,21 +69,25 @@ pub trait IntoRustByName<R> {
     fn get_by_name(&self, name: &str) -> CDRSResult<Option<R>>;
 
     fn get_r_by_name(&self, name: &str) -> CDRSResult<R> {
-        self.get_by_name(name).and_then(|op| op.ok_or(column_is_empty_err()))
+        self.get_by_name(name)
+            .and_then(|op| op.ok_or(column_is_empty_err(name)))
     }
 }
 
 pub trait ByName {
     fn by_name<R>(&self, name: &str) -> CDRSResult<Option<R>>
-        where Self: IntoRustByName<R>
+    where
+        Self: IntoRustByName<R>,
     {
         self.get_by_name(name)
     }
 
     fn r_by_name<R>(&self, name: &str) -> CDRSResult<R>
-        where Self: IntoRustByName<R>
+    where
+        Self: IntoRustByName<R>,
     {
-        self.by_name(name).and_then(|op| op.ok_or(column_is_empty_err()))
+        self.by_name(name)
+            .and_then(|op| op.ok_or(column_is_empty_err(name)))
     }
 }
 
@@ -75,21 +96,25 @@ pub trait IntoRustByIndex<R> {
     fn get_by_index(&self, index: usize) -> CDRSResult<Option<R>>;
 
     fn get_r_by_index(&self, index: usize) -> CDRSResult<R> {
-        self.get_by_index(index).and_then(|op| op.ok_or(column_is_empty_err()))
+        self.get_by_index(index)
+            .and_then(|op| op.ok_or(column_is_empty_err(index)))
     }
 }
 
 pub trait ByIndex {
     fn by_index<R>(&self, index: usize) -> CDRSResult<Option<R>>
-        where Self: IntoRustByIndex<R>
+    where
+        Self: IntoRustByIndex<R>,
     {
         self.get_by_index(index)
     }
 
     fn r_by_index<R>(&self, index: usize) -> CDRSResult<R>
-        where Self: IntoRustByIndex<R>
+    where
+        Self: IntoRustByIndex<R>,
     {
-        self.by_index(index).and_then(|op| op.ok_or(column_is_empty_err()))
+        self.by_index(index)
+            .and_then(|op| op.ok_or(column_is_empty_err(index)))
     }
 }
 
@@ -351,8 +376,9 @@ impl FromCursor for CString {
         let len: u64 = try_from_bytes(len_bytes.as_slice())?;
         let body_bytes = try!(cursor_next_value(&mut cursor, len));
 
-        String::from_utf8(body_bytes).map_err(Into::into)
-                                     .map(CString::new)
+        String::from_utf8(body_bytes)
+            .map_err(Into::into)
+            .map(CString::new)
     }
 }
 
@@ -398,8 +424,9 @@ impl FromCursor for CStringLong {
         let len: u64 = try_from_bytes(len_bytes.as_slice())?;
         let body_bytes = cursor_next_value(&mut cursor, len)?;
 
-        String::from_utf8(body_bytes).map_err(Into::into)
-                                     .map(CStringLong::new)
+        String::from_utf8(body_bytes)
+            .map_err(Into::into)
+            .map(CStringLong::new)
     }
 }
 
@@ -410,7 +437,8 @@ pub struct CStringList {
 
 impl CStringList {
     pub fn into_plain(self) -> Vec<String> {
-        self.list.iter()
+        self.list
+            .iter()
             .map(|string| string.clone().into_plain())
             .collect()
     }
@@ -436,7 +464,7 @@ impl FromCursor for CStringList {
     fn from_cursor(mut cursor: &mut Cursor<&[u8]>) -> CDRSResult<CStringList> {
         // TODO: try to use slice instead
         let mut len_bytes = [0; SHORT_LEN];
-        try!(cursor.read(&mut len_bytes));
+        try!(cursor.read_exact(&mut len_bytes));
         let len = try_from_bytes(len_bytes.to_vec().as_slice())? as usize;
         let mut list = Vec::with_capacity(len);
         for _ in 0..len {
@@ -542,8 +570,9 @@ impl FromCursor for CBytesShort {
             return Ok(CBytesShort { bytes: None });
         }
 
-        cursor_next_value(&mut cursor, len as u64).map(CBytesShort::new)
-                                                  .map_err(Into::into)
+        cursor_next_value(&mut cursor, len as u64)
+            .map(CBytesShort::new)
+            .map_err(Into::into)
     }
 }
 
@@ -628,7 +657,7 @@ pub fn cursor_next_value(cursor: &mut Cursor<&[u8]>, len: u64) -> CDRSResult<Vec
 mod tests {
     use std::io::Cursor;
     use super::*;
-    use {FromCursor, IntoBytes};
+    use frame::traits::{FromCursor, IntoBytes};
     use std::mem::transmute;
 
     // CString
diff --git a/src/types/udt.rs b/src/types/udt.rs
index b451a09..51d3827 100644
--- a/src/types/udt.rs
+++ b/src/types/udt.rs
@@ -12,7 +12,7 @@ use types::tuple::Tuple;
 use types::blob::Blob;
 use error::{column_is_empty_err, Error, Result};
 
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub struct UDT {
     data: HashMap<String, (ColTypeOption, CBytes)>,
 }
diff --git a/src/types/value.rs b/src/types/value.rs
index 7ce44ec..698ed89 100644
--- a/src/types/value.rs
+++ b/src/types/value.rs
@@ -7,7 +7,7 @@ use std::fmt::Debug;
 
 use uuid::Uuid;
 use time::Timespec;
-use IntoBytes;
+use frame::IntoBytes;
 
 use super::*;
 use super::blob::Blob;
@@ -239,7 +239,7 @@ impl<K, V> From<HashMap<K, V>> for Bytes
 mod tests {
 
     use super::*;
-    use IntoBytes;
+    use frame::traits::IntoBytes;
 
     #[test]
     fn test_value_type_into_cbytes() {


Test patch:
diff --git a/tests/collection_types.rs b/tests/collection_types.rs
index b4f379e..098631c 100644
--- a/tests/collection_types.rs
+++ b/tests/collection_types.rs
@@ -1,3 +1,4 @@
+#[macro_use]
 extern crate cdrs;
 #[macro_use]
 extern crate maplit;
@@ -10,9 +11,9 @@ mod common;
 use common::*;
 
 use uuid::Uuid;
-use cdrs::query::QueryBuilder;
+use cdrs::query::QueryExecutor;
+use cdrs::types::ByName;
 use cdrs::types::{AsRust, IntoRustByName};
-use cdrs::types::value::Value;
 use cdrs::types::list::List;
 use cdrs::types::map::Map;
 use cdrs::types::blob::Blob;
@@ -22,44 +23,40 @@ use std::collections::HashMap;
 
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn list() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_lists \
                (my_text_list frozen<list<text>> PRIMARY KEY, \
                my_nested_list list<frozen<list<int>>>)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
-    let my_text_list = vec!["text1".to_string(),
-                            "text2".to_string(),
-                            "text3".to_string()];
+    let my_text_list = vec!["text1", "text2", "text3"];
     let my_nested_list: Vec<Vec<i32>> =
         vec![vec![1, 2, 3], vec![999, 888, 777, 666, 555], vec![-1, -2]];
-    let values: Vec<Value> = vec![my_text_list.clone().into(), my_nested_list.clone().into()];
+    let values = query_values!(my_text_list.clone(), my_nested_list.clone());
 
     let cql = "INSERT INTO cdrs_test.test_lists \
                (my_text_list, my_nested_list) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    session.query_with_values(cql, values)
+           .expect("insert lists error");
 
     let cql = "SELECT * FROM cdrs_test.test_lists";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
-                      .expect("query")
+    let rows = session.query(cql)
+                      .expect("query lists error")
                       .get_body()
-                      .expect("get body")
+                      .expect("get body with lists error")
                       .into_rows()
-                      .expect("into rows");
+                      .expect("converting body with lists into rows error");
 
     assert_eq!(rows.len(), 1);
     for row in rows {
-        let my_text_list_row: List = row.get_r_by_name("my_text_list").expect("my_text_list");
         let my_text_list_row: Vec<String> =
-            my_text_list_row.as_r_rust().expect("my_text_list as rust");
-        let my_nested_list_outer_row: List =
-            row.get_r_by_name("my_nested_list").expect("my_nested_list");
+            row.r_by_name::<List>("my_text_list").expect("my_text_list")
+               .as_r_rust()
+               .expect("my_text_list as rust");
         let my_nested_list_outer_row: Vec<List> =
-            my_nested_list_outer_row.as_r_rust()
-                                    .expect("my_nested_list (outer) as rust");
+            row.r_by_name::<List>("my_nested_list").expect("my_nested_list")
+               .as_r_rust()
+               .expect("my_nested_list (outer) as rust");
         let mut my_nested_list_row = Vec::with_capacity(my_nested_list_outer_row.len());
         for my_nested_list_inner_row in my_nested_list_outer_row {
             let my_nested_list_inner_row: Vec<i32> =
@@ -67,7 +64,7 @@ fn list() {
                                         .expect("my_nested_list (inner) as rust");
             my_nested_list_row.push(my_nested_list_inner_row);
         }
-        assert_eq!(my_text_list_row, my_text_list);
+        assert_eq!(my_text_list_row, vec!["text1", "text2", "text3"]);
         assert_eq!(my_nested_list_row, my_nested_list);
     }
 }
@@ -75,28 +72,26 @@ fn list() {
 #[test]
 #[ignore]
 #[cfg(feature = "v4")]
-#[cfg(not(feature = "appveyor"))]
+#[ignore]
 fn list_v4() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_lists_v4 \
                (my_text_list frozen<list<text>> PRIMARY KEY, \
                my_nested_list list<frozen<list<smallint>>>)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
     let my_text_list = vec!["text1".to_string(),
                             "text2".to_string(),
                             "text3".to_string()];
     let my_nested_list: Vec<Vec<i16>> =
         vec![vec![1, 2, 3], vec![999, 888, 777, 666, 555], vec![-1, -2]];
-    let values: Vec<Value> = vec![my_text_list.clone().into(), my_nested_list.clone().into()];
+    let values = query_values!(my_text_list.clone(), my_nested_list.clone());
 
     let cql = "INSERT INTO cdrs_test.test_lists_v4 \
                (my_text_list, my_nested_list) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    session.query_with_values(cql, values).expect("insert");
 
     let cql = "SELECT * FROM cdrs_test.test_lists_v4";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
+    let rows = session.query(cql)
                       .expect("query")
                       .get_body()
                       .expect("get body")
@@ -105,14 +100,14 @@ fn list_v4() {
 
     assert_eq!(rows.len(), 1);
     for row in rows {
-        let my_text_list_row: List = row.get_r_by_name("my_text_list").expect("my_text_list");
         let my_text_list_row: Vec<String> =
-            my_text_list_row.as_r_rust().expect("my_text_list as rust");
-        let my_nested_list_outer_row: List =
-            row.get_r_by_name("my_nested_list").expect("my_nested_list");
+            row.r_by_name::<List>("my_text_list").expect("my_text_list")
+               .as_r_rust()
+               .expect("my_text_list as rust");
         let my_nested_list_outer_row: Vec<List> =
-            my_nested_list_outer_row.as_r_rust()
-                                    .expect("my_nested_list (outer) as rust");
+            row.r_by_name::<List>("my_nested_list").expect("my_nested_list")
+               .as_r_rust()
+               .expect("my_nested_list (outer) as rust");
         let mut my_nested_list_row = Vec::with_capacity(my_nested_list_outer_row.len());
         for my_nested_list_inner_row in my_nested_list_outer_row {
             let my_nested_list_inner_row: Vec<i16> =
@@ -127,28 +122,25 @@ fn list_v4() {
 
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn set() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_sets \
                (my_text_set frozen<set<text>> PRIMARY KEY, \
                my_nested_set set<frozen<set<int>>>)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
     let my_text_set = vec!["text1".to_string(),
                            "text2".to_string(),
                            "text3".to_string()];
     let my_nested_set: Vec<Vec<i32>> =
         vec![vec![-2, -1], vec![1, 2, 3], vec![555, 666, 777, 888, 999]];
-    let values: Vec<Value> = vec![my_text_set.clone().into(), my_nested_set.clone().into()];
+    let values = query_values!(my_text_set.clone(), my_nested_set.clone());
 
     let cql = "INSERT INTO cdrs_test.test_sets \
                (my_text_set, my_nested_set) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    session.query_with_values(cql, values).expect("insert");
 
     let cql = "SELECT * FROM cdrs_test.test_sets";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
+    let rows = session.query(cql)
                       .expect("query")
                       .get_body()
                       .expect("get body")
@@ -157,14 +149,14 @@ fn set() {
 
     assert_eq!(rows.len(), 1);
     for row in rows {
-        let my_text_set_row: List = row.get_r_by_name("my_text_set").expect("my_text_set");
         let my_text_set_row: Vec<String> =
-            my_text_set_row.as_r_rust().expect("my_text_set as rust");
-        let my_nested_set_outer_row: List =
-            row.get_r_by_name("my_nested_set").expect("my_nested_set");
+            row.r_by_name::<List>("my_text_set").expect("my_text_set")
+               .as_r_rust()
+               .expect("my_text_set as rust");
         let my_nested_set_outer_row: Vec<List> =
-            my_nested_set_outer_row.as_r_rust()
-                                   .expect("my_nested_set (outer) as rust");
+            row.r_by_name::<List>("my_nested_set").expect("my_nested_set")
+               .as_r_rust()
+               .expect("my_nested_set (outer) as rust");
         let mut my_nested_set_row = Vec::with_capacity(my_nested_set_outer_row.len());
         for my_nested_set_inner_row in my_nested_set_outer_row {
             let my_nested_set_inner_row: Vec<i32> =
@@ -180,28 +172,26 @@ fn set() {
 #[test]
 #[ignore]
 #[cfg(feature = "v4")]
-#[cfg(not(feature = "appveyor"))]
+#[ignore]
 fn set_v4() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_sets_v4 \
                (my_text_set frozen<set<text>> PRIMARY KEY, \
                my_nested_set set<frozen<set<smallint>>>)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
     let my_text_set = vec!["text1".to_string(),
                            "text2".to_string(),
                            "text3".to_string()];
     let my_nested_set: Vec<Vec<i16>> =
         vec![vec![-2, -1], vec![1, 2, 3], vec![555, 666, 777, 888, 999]];
-    let values: Vec<Value> = vec![my_text_set.clone().into(), my_nested_set.clone().into()];
+    let values = query_values!(my_text_set.clone(), my_nested_set.clone());
 
     let cql = "INSERT INTO cdrs_test.test_sets_v4 \
                (my_text_set, my_nested_set) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    session.query_with_values(cql, values).expect("insert");
 
     let cql = "SELECT * FROM cdrs_test.test_sets_v4";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
+    let rows = session.query(cql)
                       .expect("query")
                       .get_body()
                       .expect("get body")
@@ -210,14 +200,14 @@ fn set_v4() {
 
     assert_eq!(rows.len(), 1);
     for row in rows {
-        let my_text_set_row: List = row.get_r_by_name("my_text_set").expect("my_text_set");
         let my_text_set_row: Vec<String> =
-            my_text_set_row.as_r_rust().expect("my_text_set as rust");
-        let my_nested_set_outer_row: List =
-            row.get_r_by_name("my_nested_set").expect("my_nested_set");
+            row.r_by_name::<List>("my_text_set").expect("my_text_set")
+               .as_r_rust()
+               .expect("my_text_set as rust");
         let my_nested_set_outer_row: Vec<List> =
-            my_nested_set_outer_row.as_r_rust()
-                                   .expect("my_nested_set (outer) as rust");
+            row.r_by_name::<List>("my_nested_set").expect("my_nested_set")
+               .as_r_rust()
+               .expect("my_nested_set (outer) as rust");
         let mut my_nested_set_row = Vec::with_capacity(my_nested_set_outer_row.len());
         for my_nested_set_inner_row in my_nested_set_outer_row {
             let my_nested_set_inner_row: Vec<i16> =
@@ -232,13 +222,12 @@ fn set_v4() {
 
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn map_without_blob() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_maps_without_blob \
                (my_key int PRIMARY KEY, \
                my_text_map map<text, text>, \
                my_nested_map map<uuid, frozen<map<bigint, int>>>)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
     let my_text_map = hashmap!{
         "key1".to_string() => "value1".to_string(),
@@ -259,18 +248,14 @@ fn map_without_blob() {
             3 => 3,
         },
     };
-    let values: Vec<Value> = vec![0i32.into(),
-                                  my_text_map.clone().into(),
-                                  my_nested_map.clone().into()];
+    let values = query_values!(0i32, my_text_map.clone(), my_nested_map.clone());
 
     let cql = "INSERT INTO cdrs_test.test_maps_without_blob \
                (my_key, my_text_map, my_nested_map) VALUES (?, ?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    session.query_with_values(cql, values).expect("insert");
 
     let cql = "SELECT * FROM cdrs_test.test_maps_without_blob";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
+    let rows = session.query(cql)
                       .expect("query")
                       .get_body()
                       .expect("get body")
@@ -279,14 +264,14 @@ fn map_without_blob() {
 
     assert_eq!(rows.len(), 1);
     for row in rows {
-        let my_text_map_row: Map = row.get_r_by_name("my_text_map").expect("my_text_map");
         let my_text_map_row: HashMap<String, String> =
-            my_text_map_row.as_r_rust().expect("my_text_map as rust");
-        let my_nested_map_outer_row: Map =
-            row.get_r_by_name("my_nested_map").expect("my_nested_map");
+            row.r_by_name::<Map>("my_text_map").expect("my_text_map")
+               .as_r_rust()
+               .expect("my_text_map as rust");
         let my_nested_map_outer_row: HashMap<Uuid, Map> =
-            my_nested_map_outer_row.as_r_rust()
-                                   .expect("my_nested_map (outer) as rust");
+            row.r_by_name::<Map>("my_nested_map").expect("my_nested_map")
+               .as_r_rust()
+               .expect("my_nested_map (outer) as rust");
         let mut my_nested_map_row = HashMap::with_capacity(my_nested_map_outer_row.len());
         for (index, my_nested_map_inner_row) in my_nested_map_outer_row {
             let my_nested_map_inner_row: HashMap<i64, i32> =
@@ -302,12 +287,12 @@ fn map_without_blob() {
 #[test]
 #[ignore]
 #[cfg(feature = "v4")]
-#[cfg(not(feature = "appveyor"))]
+#[ignore]
 fn map_without_blob_v4() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_maps_without_blob_v4 \
                (my_text_map frozen<map<text, text>> PRIMARY KEY, \
                my_nested_map map<uuid, frozen<map<bigint, tinyint>>>)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
     let my_text_map = hashmap!{
         "key1".to_string() => "value1".to_string(),
@@ -328,16 +313,14 @@ fn map_without_blob_v4() {
             3 => 3,
         },
     };
-    let values: Vec<Value> = vec![my_text_map.clone().into(), my_nested_map.clone().into()];
+    let values = query_values!(my_text_map.clone(), my_nested_map.clone());
 
     let cql = "INSERT INTO cdrs_test.test_maps_without_blob_v4 \
                (my_text_map, my_nested_map) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    session.query_with_values(cql, values).expect("insert");
 
     let cql = "SELECT * FROM cdrs_test.test_maps_without_blob_v4";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
+    let rows = session.query(cql)
                       .expect("query")
                       .get_body()
                       .expect("get body")
@@ -346,14 +329,14 @@ fn map_without_blob_v4() {
 
     assert_eq!(rows.len(), 1);
     for row in rows {
-        let my_text_map_row: Map = row.get_r_by_name("my_text_map").expect("my_text_map");
         let my_text_map_row: HashMap<String, String> =
-            my_text_map_row.as_r_rust().expect("my_text_map as rust");
-        let my_nested_map_outer_row: Map =
-            row.get_r_by_name("my_nested_map").expect("my_nested_map");
+            row.r_by_name::<Map>("my_text_map").expect("my_text_map")
+               .as_r_rust()
+               .expect("my_text_map as rust");
         let my_nested_map_outer_row: HashMap<Uuid, Map> =
-            my_nested_map_outer_row.as_r_rust()
-                                   .expect("my_nested_map (outer) as rust");
+            row.r_by_name::<Map>("my_nested_map").expect("my_nested_map")
+               .as_r_rust()
+               .expect("my_nested_map (outer) as rust");
         let mut my_nested_map_row = HashMap::with_capacity(my_nested_map_outer_row.len());
         for (index, my_nested_map_inner_row) in my_nested_map_outer_row {
             let my_nested_map_inner_row: HashMap<i64, i8> =
@@ -368,12 +351,11 @@ fn map_without_blob_v4() {
 
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn map() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_maps \
                (my_text_map frozen<map<text, text>> PRIMARY KEY, \
                my_nested_map map<uuid, frozen<map<bigint, blob>>>)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
     let my_text_map = hashmap!{
         "key1".to_string() => "value1".to_string(),
@@ -394,16 +376,14 @@ fn map() {
             3 => vec![72, 81, 26, 173, 107, 96, 38, 91].into(),
         },
     };
-    let values: Vec<Value> = vec![my_text_map.clone().into(), my_nested_map.clone().into()];
+    let values = query_values!(my_text_map.clone(), my_nested_map.clone());
 
     let cql = "INSERT INTO cdrs_test.test_maps \
                (my_text_map, my_nested_map) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    session.query_with_values(cql, values).expect("insert");
 
     let cql = "SELECT * FROM cdrs_test.test_maps";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
+    let rows = session.query(cql)
                       .expect("query")
                       .get_body()
                       .expect("get body")
@@ -412,14 +392,14 @@ fn map() {
 
     assert_eq!(rows.len(), 1);
     for row in rows {
-        let my_text_map_row: Map = row.get_r_by_name("my_text_map").expect("my_text_map");
         let my_text_map_row: HashMap<String, String> =
-            my_text_map_row.as_r_rust().expect("my_text_map as rust");
-        let my_nested_map_outer_row: Map =
-            row.get_r_by_name("my_nested_map").expect("my_nested_map");
+            row.r_by_name::<Map>("my_text_map").expect("my_text_map")
+               .as_r_rust()
+               .expect("my_text_map as rust");
         let my_nested_map_outer_row: HashMap<Uuid, Map> =
-            my_nested_map_outer_row.as_r_rust()
-                                   .expect("my_nested_map (outer) as rust");
+            row.r_by_name::<Map>("my_nested_map").expect("my_nested_map")
+               .as_r_rust()
+               .expect("my_nested_map (outer) as rust");
         let mut my_nested_map_row = HashMap::with_capacity(my_nested_map_outer_row.len());
         for (index, my_nested_map_inner_row) in my_nested_map_outer_row {
             let my_nested_map_inner_row: HashMap<i64, Blob> =
diff --git a/tests/common/mod.rs b/tests/common/mod.rs
index c8fd126..3bc5e7c 100644
--- a/tests/common/mod.rs
+++ b/tests/common/mod.rs
@@ -1,55 +1,53 @@
 use regex::Regex;
-use cdrs::client::{CDRS, Session};
-use cdrs::query::QueryBuilder;
 use cdrs::authenticators::NoneAuthenticator;
 use cdrs::compression::Compression;
-use cdrs::transport::TransportTcp;
 use cdrs::error::Result;
+use cdrs::load_balancing::RoundRobin;
+use cdrs::cluster::{Cluster, Session};
+use cdrs::query::QueryExecutor;
+use cdrs::transport::TransportTcp;
 
 const ADDR: &'static str = "127.0.0.1:9042";
 
-pub type CSession = Session<NoneAuthenticator, TransportTcp>;
+pub type CSession = Session<RoundRobin<TransportTcp>, NoneAuthenticator>;
 
 pub fn setup(create_table_cql: &'static str) -> Result<CSession> {
-    setup_multiple(&[create_table_cql])
+  setup_multiple(&[create_table_cql])
 }
 
 pub fn setup_multiple(create_cqls: &[&'static str]) -> Result<CSession> {
-    let authenticator = NoneAuthenticator;
-    let tcp_transport = TransportTcp::new(ADDR)?;
-    let client = CDRS::new(tcp_transport, authenticator);
-    let session = client.start(Compression::None)?;
-    let re_table_name = Regex::new(r"CREATE TABLE IF NOT EXISTS (\w+\.\w+)").unwrap();
-
-    let cql = "CREATE KEYSPACE IF NOT EXISTS cdrs_test WITH \
-               replication = {'class': 'SimpleStrategy', 'replication_factor': 1} \
-               AND durable_writes = false";
-    let query = QueryBuilder::new(cql).finalize();
-    session.query(query, true, true)?;
-
-    for create_cql in create_cqls.iter() {
-        let table_name = re_table_name
-            .captures(create_cql)
-            .map(|cap| cap.get(1).unwrap().as_str());
-
-        // Re-using tables is a lot faster than creating/dropping them for every test.
-        // But if table definitions change while editing tests
-        // the old tables need to be dropped. For example by uncommenting the following lines.
-        // if let Some(table_name) = table_name {
-        //     let cql = format!("DROP TABLE IF EXISTS {}", table_name);
-        //     let query = QueryBuilder::new(cql).finalize();
-        //     session.query(query, true, true)?;
-        // }
-
-        let query = QueryBuilder::new(create_cql.to_owned()).finalize();
-        session.query(query, true, true)?;
-
-        if let Some(table_name) = table_name {
-            let cql = format!("TRUNCATE TABLE {}", table_name);
-            let query = QueryBuilder::new(cql).finalize();
-            session.query(query, true, true)?;
-        }
+  let authenticator = NoneAuthenticator {};
+  let nodes = vec!["127.0.0.1:9042"];
+  let cluster = Cluster::new(nodes, authenticator);
+  let mut session = cluster.connect(RoundRobin::new())
+                           .expect("No compression connection error");
+  let re_table_name = Regex::new(r"CREATE TABLE IF NOT EXISTS (\w+\.\w+)").unwrap();
+
+  let create_keyspace_query = "CREATE KEYSPACE IF NOT EXISTS cdrs_test WITH \
+                               replication = {'class': 'SimpleStrategy', 'replication_factor': 1} \
+                               AND durable_writes = false";
+  session.query(create_keyspace_query)?;
+
+  for create_cql in create_cqls.iter() {
+    let table_name = re_table_name.captures(create_cql)
+                                  .map(|cap| cap.get(1).unwrap().as_str());
+
+    // Re-using tables is a lot faster than creating/dropping them for every test.
+    // But if table definitions change while editing tests
+    // the old tables need to be dropped. For example by uncommenting the following lines.
+    // if let Some(table_name) = table_name {
+    //     let cql = format!("DROP TABLE IF EXISTS {}", table_name);
+    //     let query = QueryBuilder::new(cql).finalize();
+    //     session.query(query, true, true)?;
+    // }
+
+    session.query(create_cql.to_owned())?;
+
+    if let Some(table_name) = table_name {
+      let cql = format!("TRUNCATE TABLE {}", table_name);
+      session.query(cql)?;
     }
+  }
 
-    Ok(session)
+  Ok(session)
 }
diff --git a/tests/create_insert_table.rs b/tests/create_insert_table.rs
deleted file mode 100644
index 7f90222..0000000
--- a/tests/create_insert_table.rs
+++ /dev/null
@@ -1,242 +0,0 @@
-// NOTE: having crud_operations do we still need it?
-extern crate cdrs;
-extern crate env_logger;
-#[macro_use]
-extern crate log;
-
-use cdrs::client::CDRS;
-use cdrs::query::QueryBuilder;
-use cdrs::authenticators::NoneAuthenticator;
-use cdrs::compression::Compression;
-use cdrs::consistency::Consistency;
-use cdrs::transport::TransportTcp;
-use cdrs::query::QueryParamsBuilder;
-use cdrs::types::value::Value;
-use std::panic;
-use cdrs::types::IntoRustByName;
-use cdrs::types::map::Map;
-
-
-// default credentials
-const _ADDR: &'static str = "127.0.0.1:9042";
-
-
-pub struct TestContext {
-    pub client: cdrs::client::CDRS<NoneAuthenticator, TransportTcp>,
-}
-
-#[derive(Debug, Default)]
-struct User {
-    pub user_name: String,
-    pub password: String,
-    pub gender: String,
-    pub session_token: String,
-    pub state: String,
-    pub some_map: Option<Map>,
-}
-
-#[test]
-#[ignore]
-#[cfg(not(feature = "appveyor"))]
-fn write_and_read_from_cassandra() {
-    run_test(|| read_write())
-}
-
-fn read_write() {
-    println!("read_write");
-    insert_data_users();
-    read_from_user_table();
-}
-
-///
-/// right now we don't have setup and teardown that is the reason for this monstrosity
-/// there might be better ways to write testing code; have to revisit later
-/// the flow goes likes this
-/// 1. setup() ==> create new keyspace -> create new tables
-/// 2. read_write ==>
-///     a) insert_data_users()
-///     b) read_from_user_table()
-/// 3. teardown() ==> drop the keyspace
-fn run_test<T>(test: T) -> ()
-    where T: FnOnce() -> () + panic::UnwindSafe
-{
-    setup();
-
-    let result = panic::catch_unwind(|| test());
-
-    teardown();
-
-    assert!(result.is_ok())
-}
-
-fn setup() {
-    create_keyspace();
-    create_table();
-}
-
-fn teardown() {
-    drop_keyspace();
-}
-
-
-fn insert_data_users() {
-    println!("insert_data_users");
-    let ctx = TestContext::new();
-    let session = ctx.client.start(Compression::None).unwrap();
-    let insert_table_cql = "INSERT INTO user_keyspace.users
-            (user_name, password, gender, session_token, state)
-    VALUES (?, ?, ?, ?, ?)";
-
-    let prepared = session.prepare(insert_table_cql.to_string(), true, true)
-                          .unwrap()
-                          .get_body()
-                          .unwrap()
-                          .into_prepared()
-                          .unwrap();
-
-    println!("prepared:\n{:?}", prepared);
-
-    let v: Vec<Value> = vec!["harry".into(),
-                             "pwd".into(),
-                             "male".into(),
-                             "09000".into(),
-                             "FL".into()];
-    let execution_params = QueryParamsBuilder::new(Consistency::One).values(v)
-                                                                    .finalize();
-
-    let ref query_id = prepared.id;
-    let executed = session.execute(query_id, execution_params, true, true);
-
-    info!("executed:\n{:?}", executed);
-}
-
-fn read_from_user_table() {
-    println!("read_from_user_table");
-    let ctx = TestContext::new();
-    let session = ctx.client.start(Compression::None).unwrap();
-    let select_query = QueryBuilder::new(
-        "\
-        SELECT user_name, password, gender, session_token, state, some_map \
-        FROM user_keyspace.users",
-    ).finalize();
-
-    let query_op = session.query(select_query, true, true);
-
-    match query_op {
-        Ok(res) => {
-            let res_body = res.get_body().expect("shold have body");
-            if let Some(rows) = res_body.into_rows() {
-                let users: Vec<User> =
-                    rows.iter().map(|row| {
-                                 let mut user = User { ..Default::default() };
-                                 if let Ok(Some(user_name)) = row.get_by_name("user_name") {
-                                     user.user_name = user_name;
-                                 }
-
-                                 if let Ok(Some(password)) = row.get_by_name("password") {
-                                     user.password = password;
-                                 }
-
-                                 if let Ok(Some(gender)) = row.get_by_name("gender") {
-                                     user.gender = gender;
-                                 }
-
-                                 if let Ok(Some(session_token)) = row.get_by_name("session_token") {
-                                     user.session_token = session_token;
-                                 }
-
-                                 if let Ok(Some(state)) = row.get_by_name("state") {
-                                     user.state = state;
-                                 }
-
-                                 if let Ok(Some(m)) = row.get_by_name("some_map") {
-                                     user.some_map = Some(m);
-                                 }
-
-                                 user
-                             })
-                        .collect();
-                println!("Users {:?}", users);
-
-
-                assert_eq!(users[0].user_name, "harry");
-                assert_eq!(users[0].password, "pwd");
-                assert_eq!(users[0].gender, "male");
-                assert_eq!(users[0].state, "FL");
-            }
-        }
-        Err(err) => println!("{:?}", err),
-    }
-}
-
-
-impl TestContext {
-    fn new() -> TestContext {
-        const _ADDR: &'static str = "127.0.0.1:9042";
-        let authenticator = NoneAuthenticator;
-        let tcp_transport = TransportTcp::new(_ADDR);
-        let client = CDRS::new(tcp_transport.unwrap(), authenticator);
-        TestContext { client: client }
-    }
-}
-
-
-fn create_keyspace() {
-    let ctx = TestContext::new();
-    let session = ctx.client.start(Compression::None).unwrap();
-    let create_ks_cql = "CREATE KEYSPACE IF NOT EXISTS user_keyspace WITH REPLICATION = { 'class' \
-                         : 'SimpleStrategy', 'replication_factor' : 1 } ;";
-
-    let create_ks_query = QueryBuilder::new(create_ks_cql).consistency(Consistency::One)
-                                                          .finalize();
-
-    let create_ks_query_result = session.query(create_ks_query, false, false);
-
-    assert_eq!(create_ks_query_result.is_ok(), true);
-}
-
-
-fn create_table() {
-    let ctx = TestContext::new();
-    let session = ctx.client.start(Compression::None).unwrap();
-    let create_table_cql = "CREATE TABLE IF NOT EXISTS user_keyspace.users (
-        user_name varchar PRIMARY KEY,
-        password varchar,
-        gender varchar,
-        session_token varchar,
-        state varchar,
-        birth_year bigint,
-        some_map map<text, text>
-    );";
-
-    let create_table_query = QueryBuilder::new(create_table_cql).consistency(Consistency::One)
-                                                                .finalize();
-
-    let create_table_query_result = session.query(create_table_query, false, false);
-
-    assert_eq!(create_table_query_result.is_ok(), true);
-
-    match create_table_query_result {
-        Ok(ref res) => println!("table created: {:?}", res.get_body()),
-        Err(ref err) => println!("Error occured: {:?}", err),
-    }
-}
-
-fn drop_keyspace() {
-    let ctx = TestContext::new();
-    let session = ctx.client.start(Compression::None).unwrap();
-    let drop_ks = "DROP KEYSPACE IF EXISTS user_keyspace;";
-    let with_tracing = false;
-    let with_warnings = false;
-    let drop_ks_query = QueryBuilder::new(drop_ks).consistency(Consistency::One)
-                                                  .finalize();
-    let drop_ks_query_result = session.query(drop_ks_query, with_tracing, with_warnings);
-
-    assert!(drop_ks_query_result.is_ok(),
-            "drop keyspace - query builder failed");
-
-    match drop_ks_query_result {
-        Ok(ref res) => println!("keyspace dropped: {:?}", res.get_body()),
-        Err(ref err) => println!("Error occured: {:?}", err),
-    }
-}
diff --git a/tests/derive_traits.rs b/tests/derive_traits.rs
new file mode 100644
index 0000000..21a311b
--- /dev/null
+++ b/tests/derive_traits.rs
@@ -0,0 +1,234 @@
+#[macro_use]
+extern crate cdrs;
+#[macro_use]
+extern crate cdrs_helpers_derive;
+#[macro_use]
+extern crate maplit;
+extern crate regex;
+extern crate time;
+extern crate uuid;
+
+mod common;
+
+use common::*;
+
+use cdrs::query::QueryValues;
+use cdrs::query::QueryExecutor;
+use cdrs::types::{AsRust, AsRustType, IntoRustByName};
+use cdrs::types::value::{Bytes, Value};
+use cdrs::types::rows::Row;
+use cdrs::types::udt::UDT;
+use cdrs::types::map::Map;
+use cdrs::error::Result as CDRSResult;
+use cdrs::frame::IntoBytes;
+use time::Timespec;
+use cdrs::frame::{TryFromRow, TryFromUDT};
+use cdrs::types::from_cdrs::FromCDRSByName;
+
+use std::collections::HashMap;
+
+#[test]
+#[ignore]
+fn simple_udt() {
+  let create_type_cql = "CREATE TYPE IF NOT EXISTS cdrs_test.derive_udt (my_text text)";
+  let create_table_cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_derived_udt \
+                          (my_key int PRIMARY KEY, my_udt derive_udt)";
+  let mut session = setup_multiple(&[create_type_cql, create_table_cql]).expect("setup");
+
+  #[derive(Clone, Debug, IntoCDRSValue, TryFromRow, PartialEq)]
+  struct RowStruct {
+    my_key: i32,
+    my_udt: MyUdt,
+  }
+
+  impl RowStruct {
+    fn into_query_values(self) -> QueryValues {
+      query_values!("my_key" => self.my_key, "my_udt" => self.my_udt)
+    }
+  }
+
+  #[derive(Debug, Clone, PartialEq, IntoCDRSValue, TryFromUDT)]
+  struct MyUdt {
+    pub my_text: String,
+  }
+
+  let row_struct = RowStruct {
+    my_key: 1i32,
+    my_udt: MyUdt {
+      my_text: "my_text".to_string(),
+    },
+  };
+
+  let cql = "INSERT INTO cdrs_test.test_derived_udt \
+             (my_key, my_udt) VALUES (?, ?)";
+  session
+    .query_with_values(cql, row_struct.clone().into_query_values())
+    .expect("insert");
+
+  let cql = "SELECT * FROM cdrs_test.test_derived_udt";
+  let rows = session
+    .query(cql)
+    .expect("query")
+    .get_body()
+    .expect("get body")
+    .into_rows()
+    .expect("into rows");
+
+  assert_eq!(rows.len(), 1);
+  for row in rows {
+    let my_udt_row: RowStruct = RowStruct::try_from_row(row).expect("into RowStruct");
+    assert_eq!(my_udt_row, row_struct);
+  }
+}
+
+#[test]
+#[ignore]
+fn nested_udt() {
+  let create_type1_cql = "CREATE TYPE IF NOT EXISTS cdrs_test.nested_inner_udt (my_text text)";
+  let create_type2_cql = "CREATE TYPE IF NOT EXISTS cdrs_test.nested_outer_udt \
+                          (my_inner_udt frozen<nested_inner_udt>)";
+  let create_table_cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_nested_udt \
+                          (my_key int PRIMARY KEY, my_outer_udt nested_outer_udt)";
+  let mut session =
+    setup_multiple(&[create_type1_cql, create_type2_cql, create_table_cql]).expect("setup");
+
+  #[derive(Clone, Debug, IntoCDRSValue, TryFromRow, PartialEq)]
+  struct RowStruct {
+    my_key: i32,
+    my_outer_udt: MyOuterUdt,
+  }
+
+  impl RowStruct {
+    fn into_query_values(self) -> QueryValues {
+      query_values!("my_key" => self.my_key, "my_outer_udt" => self.my_outer_udt)
+    }
+  }
+
+  #[derive(Clone, Debug, IntoCDRSValue, TryFromUDT, PartialEq)]
+  struct MyInnerUdt {
+    pub my_text: String,
+  }
+
+  #[derive(Clone, Debug, IntoCDRSValue, TryFromUDT, PartialEq)]
+  struct MyOuterUdt {
+    pub my_inner_udt: MyInnerUdt,
+  }
+
+  let row_struct = RowStruct {
+    my_key: 0,
+    my_outer_udt: MyOuterUdt {
+      my_inner_udt: MyInnerUdt {
+        my_text: "my_text".to_string(),
+      },
+    },
+  };
+
+  let cql = "INSERT INTO cdrs_test.test_nested_udt \
+             (my_key, my_outer_udt) VALUES (?, ?)";
+  session
+    .query_with_values(cql, row_struct.clone().into_query_values())
+    .expect("insert");
+
+  let cql = "SELECT * FROM cdrs_test.test_nested_udt";
+  let rows = session
+    .query(cql)
+    .expect("query")
+    .get_body()
+    .expect("get body")
+    .into_rows()
+    .expect("into rows");
+
+  assert_eq!(rows.len(), 1);
+  for row in rows {
+    let my_row_struct: RowStruct = RowStruct::try_from_row(row).expect("into RowStruct");
+    assert_eq!(my_row_struct, row_struct);
+  }
+}
+
+#[test]
+#[ignore]
+fn alter_udt_add() {
+  let drop_table_cql = "DROP TABLE IF EXISTS cdrs_test.test_alter_udt_add";
+  let drop_type_cql = "DROP TYPE IF EXISTS cdrs_test.alter_udt_add_udt";
+  let create_type_cql = "CREATE TYPE cdrs_test.alter_udt_add_udt (my_text text)";
+  let create_table_cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_alter_udt_add \
+                          (my_key int PRIMARY KEY, my_map frozen<map<text, alter_udt_add_udt>>)";
+  let mut session = setup_multiple(&[
+    drop_table_cql,
+    drop_type_cql,
+    create_type_cql,
+    create_table_cql,
+  ]).expect("setup");
+
+  #[derive(Clone, Debug, IntoCDRSValue, TryFromRow, PartialEq)]
+  struct RowStruct {
+    my_key: i32,
+    my_map: HashMap<String, MyUdtA>,
+  }
+
+  impl RowStruct {
+    fn into_query_values(self) -> QueryValues {
+      query_values!("my_key" => self.my_key, "my_map" => self.my_map)
+    }
+  }
+
+  #[derive(Clone, Debug, IntoCDRSValue, TryFromUDT, PartialEq)]
+  struct MyUdtA {
+    pub my_text: String,
+  }
+
+  #[derive(Clone, Debug, IntoCDRSValue, TryFromRow, PartialEq)]
+  struct RowStructB {
+    my_key: i32,
+    my_map: HashMap<String, MyUdtB>,
+  }
+
+  impl RowStructB {
+    fn into_query_values(self) -> QueryValues {
+      query_values!("my_key" => self.my_key, "my_map" => self.my_map)
+    }
+  }
+
+  #[derive(Clone, Debug, IntoCDRSValue, TryFromUDT, PartialEq)]
+  struct MyUdtB {
+    pub my_text: String,
+    pub my_timestamp: Option<Timespec>,
+  }
+
+  let row_struct = RowStruct {
+    my_key: 0,
+    my_map: hashmap! { "1".to_string() => MyUdtA {my_text: "my_text".to_string()} },
+  };
+
+  let cql = "INSERT INTO cdrs_test.test_alter_udt_add \
+             (my_key, my_map) VALUES (?, ?)";
+  session
+    .query_with_values(cql, row_struct.clone().into_query_values())
+    .expect("insert");
+
+  let cql = "ALTER TYPE cdrs_test.alter_udt_add_udt ADD my_timestamp timestamp";
+  session.query(cql).expect("alter type");
+
+  let expected_nested_udt = MyUdtB {
+    my_text: "my_text".to_string(),
+    my_timestamp: None,
+  };
+
+  let cql = "SELECT * FROM cdrs_test.test_alter_udt_add";
+  let rows = session
+    .query(cql)
+    .expect("query")
+    .get_body()
+    .expect("get body")
+    .into_rows()
+    .expect("into rows");
+
+  assert_eq!(rows.len(), 1);
+  for row in rows {
+    let altered_row: RowStructB = RowStructB::try_from_row(row).expect("into RowStructB");
+    assert_eq!(
+      altered_row.my_map,
+      hashmap! { "1".to_string() => expected_nested_udt.clone() }
+    );
+  }
+}
diff --git a/tests/keyspace.rs b/tests/keyspace.rs
index 7f4a3c2..ba1703c 100644
--- a/tests/keyspace.rs
+++ b/tests/keyspace.rs
@@ -2,48 +2,40 @@ extern crate cdrs;
 
 use std::collections::HashMap;
 
-use cdrs::types::ByName;
-use cdrs::client::CDRS;
-use cdrs::query::QueryBuilder;
-use cdrs::types::{AsRust, IntoRustByName};
 use cdrs::authenticators::NoneAuthenticator;
-use cdrs::compression::Compression;
-use cdrs::transport::TransportTcp;
+use cdrs::cluster::Cluster;
+use cdrs::load_balancing::RoundRobin;
+use cdrs::query::QueryExecutor;
+use cdrs::types::{AsRust, ByName, IntoRustByName};
 use cdrs::types::map::Map;
 
 const ADDR: &'static str = "127.0.0.1:9042";
 
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn create_keyspace() {
-        let authenticator = NoneAuthenticator;
-        let tcp_transport = TransportTcp::new(ADDR).expect("create transport");
-        let client = CDRS::new(tcp_transport, authenticator);
-        let session = client.start(Compression::None).expect("start session");
-
-        let drop_ks_cql = "DROP KEYSPACE IF EXISTS create_ks_test";
-        let drop_query = QueryBuilder::new(drop_ks_cql).finalize();
-        let keyspace_droped = session.query(drop_query, false, false).is_ok();
+        let cluster = Cluster::new(vec!["127.0.0.1:9042"], NoneAuthenticator {});
+        let mut session =
+                cluster.connect(RoundRobin::new()).expect("No compression connection error");
+
+        let drop_query = "DROP KEYSPACE IF EXISTS create_ks_test";
+        let keyspace_droped = session.query(drop_query).is_ok();
         assert!(keyspace_droped, "Should drop new keyspace without errors");
 
-        let create_ks_cql = "CREATE KEYSPACE IF NOT EXISTS create_ks_test WITH \
-                             replication = {'class': 'SimpleStrategy', 'replication_factor': 1} \
-                             AND durable_writes = false";
-        let create_query = QueryBuilder::new(create_ks_cql).finalize();
-        let keyspace_created = session.query(create_query, false, false).is_ok();
+        let create_query = "CREATE KEYSPACE IF NOT EXISTS create_ks_test WITH \
+                            replication = {'class': 'SimpleStrategy', 'replication_factor': 1} \
+                            AND durable_writes = false";
+        let keyspace_created = session.query(create_query).is_ok();
         assert!(keyspace_created,
                 "Should create new keyspace without errors");
 
-        let select_ks_cql =
+        let select_query =
                 "SELECT * FROM system_schema.keyspaces WHERE keyspace_name = 'create_ks_test'";
-        let select_query = QueryBuilder::new(select_ks_cql).finalize();
-        let keyspace_selected =
-                session.query(select_query, false, false).expect("select keyspace query")
-                       .get_body()
-                       .expect("get select keyspace query body")
-                       .into_rows()
-                       .expect("convert keyspaces results into rows");
+        let keyspace_selected = session.query(select_query).expect("select keyspace query")
+                                       .get_body()
+                                       .expect("get select keyspace query body")
+                                       .into_rows()
+                                       .expect("convert keyspaces results into rows");
 
         assert_eq!(keyspace_selected.len(), 1);
         let keyspace = &keyspace_selected[0];
@@ -74,42 +66,35 @@ fn create_keyspace() {
 
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn alter_keyspace() {
-        let authenticator = NoneAuthenticator;
-        let tcp_transport = TransportTcp::new(ADDR).expect("create transport");
-        let client = CDRS::new(tcp_transport, authenticator);
-        let session = client.start(Compression::None).expect("start session");
-
-        let drop_ks_cql = "DROP KEYSPACE IF EXISTS alter_ks_test";
-        let drop_query = QueryBuilder::new(drop_ks_cql).finalize();
-        let keyspace_droped = session.query(drop_query, false, false).is_ok();
+        let cluster = Cluster::new(vec!["127.0.0.1:9042"], NoneAuthenticator {});
+        let mut session =
+                cluster.connect(RoundRobin::new()).expect("No compression connection error");
+
+        let drop_query = "DROP KEYSPACE IF EXISTS alter_ks_test";
+        let keyspace_droped = session.query(drop_query).is_ok();
         assert!(keyspace_droped, "Should drop new keyspace without errors");
 
-        let create_ks_cql = "CREATE KEYSPACE IF NOT EXISTS alter_ks_test WITH \
-                             replication = {'class': 'SimpleStrategy', 'replication_factor': 1} \
-                             AND durable_writes = false";
-        let create_query = QueryBuilder::new(create_ks_cql).finalize();
-        let keyspace_created = session.query(create_query, false, false).is_ok();
+        let create_query = "CREATE KEYSPACE IF NOT EXISTS alter_ks_test WITH \
+                            replication = {'class': 'SimpleStrategy', 'replication_factor': 1} \
+                            AND durable_writes = false";
+        let keyspace_created = session.query(create_query).is_ok();
         assert!(keyspace_created,
                 "Should create new keyspace without errors");
 
-        let alter_ks_cql = "ALTER KEYSPACE alter_ks_test WITH \
-                            replication = {'class': 'SimpleStrategy', 'replication_factor': 3} \
-                            AND durable_writes = false";
-        let alter_query = QueryBuilder::new(alter_ks_cql).finalize();
-        assert!(session.query(alter_query, false, false).is_ok(),
+        let alter_query = "ALTER KEYSPACE alter_ks_test WITH \
+                           replication = {'class': 'SimpleStrategy', 'replication_factor': 3} \
+                           AND durable_writes = false";
+        assert!(session.query(alter_query).is_ok(),
                 "alter should be without errors");
 
-        let select_ks_cql =
+        let select_query =
                 "SELECT * FROM system_schema.keyspaces WHERE keyspace_name = 'alter_ks_test'";
-        let select_query = QueryBuilder::new(select_ks_cql).finalize();
-        let keyspace_selected =
-                session.query(select_query, false, false).expect("select keyspace query")
-                       .get_body()
-                       .expect("get select keyspace query body")
-                       .into_rows()
-                       .expect("convert keyspaces results into rows");
+        let keyspace_selected = session.query(select_query).expect("select keyspace query")
+                                       .get_body()
+                                       .expect("get select keyspace query body")
+                                       .into_rows()
+                                       .expect("convert keyspaces results into rows");
 
         assert_eq!(keyspace_selected.len(), 1);
         let keyspace = &keyspace_selected[0];
@@ -127,25 +112,20 @@ fn alter_keyspace() {
 
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn use_keyspace() {
-        let authenticator = NoneAuthenticator;
-        let tcp_transport = TransportTcp::new(ADDR).expect("create transport");
-        let client = CDRS::new(tcp_transport, authenticator);
-        let session = client.start(Compression::None).expect("start session");
-
-        let create_ks_cql = "CREATE KEYSPACE IF NOT EXISTS use_ks_test WITH \
-                             replication = {'class': 'SimpleStrategy', 'replication_factor': 1} \
-                             AND durable_writes = false";
-        let create_query = QueryBuilder::new(create_ks_cql).finalize();
-        let keyspace_created = session.query(create_query, false, false).is_ok();
+        let cluster = Cluster::new(vec!["127.0.0.1:9042"], NoneAuthenticator {});
+        let mut session =
+                cluster.connect(RoundRobin::new()).expect("No compression connection error");
+
+        let create_query = "CREATE KEYSPACE IF NOT EXISTS use_ks_test WITH \
+                            replication = {'class': 'SimpleStrategy', 'replication_factor': 1} \
+                            AND durable_writes = false";
+        let keyspace_created = session.query(create_query).is_ok();
         assert!(keyspace_created,
                 "Should create new keyspace without errors");
 
-        let use_ks_cql = "USE use_ks_test";
-
-        let use_query = QueryBuilder::new(use_ks_cql).finalize();
-        let keyspace_used = session.query(use_query, false, false).expect("should use selected")
+        let use_query = "USE use_ks_test";
+        let keyspace_used = session.query(use_query).expect("should use selected")
                                    .get_body()
                                    .expect("should get body")
                                    .into_set_keyspace()
@@ -156,23 +136,19 @@ fn use_keyspace() {
 
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn drop_keyspace() {
-        let authenticator = NoneAuthenticator;
-        let tcp_transport = TransportTcp::new(ADDR).expect("create transport");
-        let client = CDRS::new(tcp_transport, authenticator);
-        let session = client.start(Compression::None).expect("start session");
-
-        let create_ks_cql = "CREATE KEYSPACE IF NOT EXISTS drop_ks_test WITH \
-                             replication = {'class': 'SimpleStrategy', 'replication_factor': 1} \
-                             AND durable_writes = false";
-        let create_query = QueryBuilder::new(create_ks_cql).finalize();
-        let keyspace_created = session.query(create_query, false, false).is_ok();
+        let cluster = Cluster::new(vec!["127.0.0.1:9042"], NoneAuthenticator {});
+        let mut session =
+                cluster.connect(RoundRobin::new()).expect("No compression connection error");
+
+        let create_query = "CREATE KEYSPACE IF NOT EXISTS drop_ks_test WITH \
+                            replication = {'class': 'SimpleStrategy', 'replication_factor': 1} \
+                            AND durable_writes = false";
+        let keyspace_created = session.query(create_query).is_ok();
         assert!(keyspace_created,
                 "Should create new keyspace without errors");
 
-        let drop_ks_cql = "DROP KEYSPACE drop_ks_test";
-        let drop_query = QueryBuilder::new(drop_ks_cql).finalize();
-        let keyspace_droped = session.query(drop_query, false, false).is_ok();
+        let drop_query = "DROP KEYSPACE drop_ks_test";
+        let keyspace_droped = session.query(drop_query).is_ok();
         assert!(keyspace_droped, "Should drop new keyspace without errors");
 }
diff --git a/tests/native_types.rs b/tests/native_types.rs
index bcb8789..81ca746 100644
--- a/tests/native_types.rs
+++ b/tests/native_types.rs
@@ -1,3 +1,4 @@
+#[macro_use]
 extern crate cdrs;
 extern crate regex;
 extern crate time;
@@ -8,11 +9,11 @@ mod common;
 use common::*;
 
 use uuid::Uuid;
-use cdrs::query::QueryBuilder;
 use cdrs::types::map::Map;
 use cdrs::types::value::{Bytes, Value};
 use cdrs::types::{AsRust, ByName, IntoRustByName};
 use cdrs::types::blob::Blob;
+use cdrs::query::QueryExecutor;
 
 use std::str::FromStr;
 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
@@ -20,32 +21,28 @@ use std::collections::HashMap;
 
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn string() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_string \
                (my_ascii ascii PRIMARY KEY, my_text text, my_varchar varchar)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
-    let my_ascii = "my_ascii".to_string();
-    let my_text = "my_text".to_string();
-    let my_varchar = "my_varchar".to_string();
-    let values: Vec<Value> = vec![my_ascii.clone().into(),
-                                  my_text.clone().into(),
-                                  my_varchar.clone().into()];
+    let my_ascii = "my_ascii";
+    let my_text = "my_text";
+    let my_varchar = "my_varchar";
+    let values = query_values!(my_ascii, my_text, my_varchar);
 
-    let cql = "INSERT INTO cdrs_test.test_string \
-               (my_ascii, my_text, my_varchar) VALUES (?, ?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    let query = "INSERT INTO cdrs_test.test_string \
+                 (my_ascii, my_text, my_varchar) VALUES (?, ?, ?)";
+    session.query_with_values(query, values)
+           .expect("insert stings error");
 
     let cql = "SELECT * FROM cdrs_test.test_string";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
-                      .expect("query")
+    let rows = session.query(cql)
+                      .expect("select strings query error")
                       .get_body()
-                      .expect("get body")
+                      .expect("get body error")
                       .into_rows()
-                      .expect("into rows");
+                      .expect("converting into rows error");
 
     assert_eq!(rows.len(), 1);
     for row in rows {
@@ -60,29 +57,26 @@ fn string() {
 
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn counter() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_counter \
                (my_bigint bigint PRIMARY KEY, my_counter counter)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
     let my_bigint: i64 = 10_000_000_000_000_000;
     let my_counter: i64 = 100_000_000;
-    let values: Vec<Value> = vec![my_counter.into(), my_bigint.into()];
+    let values = query_values!(my_counter, my_bigint);
 
-    let cql = "UPDATE cdrs_test.test_counter SET my_counter = my_counter + ? \
-               WHERE my_bigint = ?";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    let query = "UPDATE cdrs_test.test_counter SET my_counter = my_counter + ? \
+                 WHERE my_bigint = ?";
+    session.query_with_values(query, values).expect("insert");
 
     let cql = "SELECT * FROM cdrs_test.test_counter";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
-                      .expect("query")
+    let rows = session.query(cql)
+                      .expect("select counter query error")
                       .get_body()
-                      .expect("get body")
+                      .expect("get counter body error")
                       .into_rows()
-                      .expect("into rows");
+                      .expect("converting coutner body into rows error");
 
     assert_eq!(rows.len(), 1);
     for row in rows {
@@ -96,30 +90,28 @@ fn counter() {
 // TODO varint
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn integer() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_integer \
                (my_bigint bigint PRIMARY KEY, my_int int, my_boolean boolean)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
     let my_bigint: i64 = 10_000_000_000_000_000;
     let my_int: i32 = 100_000_000;
     let my_boolean: bool = true;
-    let values: Vec<Value> = vec![my_bigint.into(), my_int.into(), my_boolean.into()];
+    let values = query_values!(my_bigint, my_int, my_boolean);
 
-    let cql = "INSERT INTO cdrs_test.test_integer \
-               (my_bigint, my_int, my_boolean) VALUES (?, ?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    let query = "INSERT INTO cdrs_test.test_integer \
+                 (my_bigint, my_int, my_boolean) VALUES (?, ?, ?)";
+    session.query_with_values(query, values)
+           .expect("insert integers error");
 
     let cql = "SELECT * FROM cdrs_test.test_integer";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
-                      .expect("query")
+    let rows = session.query(cql)
+                      .expect("select integers query error")
                       .get_body()
-                      .expect("get body")
+                      .expect("get body with integers error")
                       .into_rows()
-                      .expect("into rows");
+                      .expect("converting body with integers into rows error");
 
     assert_eq!(rows.len(), 1);
     for row in rows {
@@ -136,37 +128,32 @@ fn integer() {
 #[test]
 #[ignore]
 #[cfg(feature = "v4")]
-#[cfg(not(feature = "appveyor"))]
+#[ignore]
 fn integer_v4() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_integer_v4 \
                (my_bigint bigint PRIMARY KEY, my_int int, my_smallint smallint, \
                my_tinyint tinyint, my_boolean boolean)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
     let my_bigint: i64 = 10_000_000_000_000_000;
     let my_int: i32 = 100_000_000;
     let my_smallint: i16 = 10_000;
     let my_tinyint: i8 = 100;
     let my_boolean: bool = true;
-    let values: Vec<Value> = vec![my_bigint.into(),
-                                  my_int.into(),
-                                  my_smallint.into(),
-                                  my_tinyint.into(),
-                                  my_boolean.into()];
+    let values = query_values!(my_bigint, my_int, my_smallint, my_tinyint, my_boolean);
 
-    let cql = "INSERT INTO cdrs_test.test_integer_v4 \
-               (my_bigint, my_int, my_smallint, my_tinyint, my_boolean) VALUES (?, ?, ?, ?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    let query = "INSERT INTO cdrs_test.test_integer_v4 \
+                 (my_bigint, my_int, my_smallint, my_tinyint, my_boolean) VALUES (?, ?, ?, ?, ?)";
+    session.query_with_values(query, values)
+           .expect("insert integers error");
 
     let cql = "SELECT * FROM cdrs_test.test_integer_v4";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
-                      .expect("query")
+    let rows = session.query(cql)
+                      .expect("query integers error")
                       .get_body()
-                      .expect("get body")
+                      .expect("get body with integers error")
                       .into_rows()
-                      .expect("into rows");
+                      .expect("converting body with integers into rows error");
 
     assert_eq!(rows.len(), 1);
     for row in rows {
@@ -186,28 +173,26 @@ fn integer_v4() {
 // TODO decimal
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn float() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_float \
                (my_float float PRIMARY KEY, my_double double)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
     let my_float: f32 = 123.456;
     let my_double: f64 = 987.654;
-    let values: Vec<Value> = vec![my_float.into(), my_double.into()];
+    let values = query_values!(my_float, my_double);
 
-    let cql = "INSERT INTO cdrs_test.test_float (my_float, my_double) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    let query = "INSERT INTO cdrs_test.test_float (my_float, my_double) VALUES (?, ?)";
+    session.query_with_values(query, values)
+           .expect("insert floats error");
 
     let cql = "SELECT * FROM cdrs_test.test_float";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
-                      .expect("query")
+    let rows = session.query(cql)
+                      .expect("query floats error")
                       .get_body()
-                      .expect("get body")
+                      .expect("get body with floats error")
                       .into_rows()
-                      .expect("into rows");
+                      .expect("converting body with floats into rows error");
 
     assert_eq!(rows.len(), 1);
     for row in rows {
@@ -220,18 +205,18 @@ fn float() {
 
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn blob() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_blob \
                (my_blob blob PRIMARY KEY, my_mapblob map<text, blob>)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
     let my_blob: Blob = vec![0, 1, 2, 4, 8, 16, 32, 64, 128, 255].into();
-    let my_map: HashMap<String, Blob> = [("a".to_owned(), b"aaaaa".to_vec().into()),
-                                         ("b".to_owned(), b"bbbbb".to_vec().into()),
-                                         ("c".to_owned(), b"ccccc".to_vec().into()),
-                                         ("d".to_owned(), b"ddddd".to_vec().into())]
-        .into_iter()
+    let my_map: HashMap<String, Blob> = [
+        ("a".to_owned(), b"aaaaa".to_vec().into()),
+        ("b".to_owned(), b"bbbbb".to_vec().into()),
+        ("c".to_owned(), b"ccccc".to_vec().into()),
+        ("d".to_owned(), b"ddddd".to_vec().into()),
+    ].into_iter()
         .map(|x| x.clone())
         .collect();
 
@@ -240,20 +225,19 @@ fn blob() {
                                                 .map(|(k, v)| (k, Bytes::new(v.into_vec())))
                                                 .collect();
 
-    let values: Vec<Value> = vec![my_blob.clone().into(), val_map.into()];
+    let values = query_values!(my_blob.clone(), val_map);
 
-    let cql = "INSERT INTO cdrs_test.test_blob (my_blob, my_mapblob) VALUES (?,?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    let query = "INSERT INTO cdrs_test.test_blob (my_blob, my_mapblob) VALUES (?,?)";
+    session.query_with_values(query, values)
+           .expect("insert blob error");
 
     let cql = "SELECT * FROM cdrs_test.test_blob";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
-                      .expect("query")
+    let rows = session.query(cql)
+                      .expect("query blobs error")
                       .get_body()
-                      .expect("get body")
+                      .expect("get body with blobs error")
                       .into_rows()
-                      .expect("into rows");
+                      .expect("converting body with blobs into rows error");
 
     assert_eq!(rows.len(), 1);
     for row in rows {
@@ -270,27 +254,25 @@ fn blob() {
 // TODO timeuuid
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn uuid() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_uuid \
                (my_uuid uuid PRIMARY KEY)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
     let my_uuid = Uuid::from_str("bb16106a-10bc-4a07-baa3-126ffe208c43").unwrap();
-    let values: Vec<Value> = vec![my_uuid.into()];
+    let values = query_values!(my_uuid);
 
-    let cql = "INSERT INTO cdrs_test.test_uuid (my_uuid) VALUES (?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    let query = "INSERT INTO cdrs_test.test_uuid (my_uuid) VALUES (?)";
+    session.query_with_values(query, values)
+           .expect("insert UUID error");
 
     let cql = "SELECT * FROM cdrs_test.test_uuid";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
-                      .expect("query")
+    let rows = session.query(cql)
+                      .expect("query UUID error")
                       .get_body()
-                      .expect("get body")
+                      .expect("get body with UUID error")
                       .into_rows()
-                      .expect("into rows");
+                      .expect("convertion body with UUID into rows error");
 
     assert_eq!(rows.len(), 1);
     for row in rows {
@@ -302,27 +284,25 @@ fn uuid() {
 // TODO date, time, duration
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn time() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_time \
                (my_timestamp timestamp PRIMARY KEY)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
     let my_timestamp = time::get_time();
-    let values: Vec<Value> = vec![my_timestamp.into()];
+    let values = query_values!(my_timestamp);
 
-    let cql = "INSERT INTO cdrs_test.test_time (my_timestamp) VALUES (?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    let query = "INSERT INTO cdrs_test.test_time (my_timestamp) VALUES (?)";
+    session.query_with_values(query, values)
+           .expect("insert timestamp error");
 
     let cql = "SELECT * FROM cdrs_test.test_time";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
-                      .expect("query")
+    let rows = session.query(cql)
+                      .expect("query with time error")
                       .get_body()
-                      .expect("get body")
+                      .expect("get body with time error")
                       .into_rows()
-                      .expect("into rows");
+                      .expect("converting body with time into rows error");
 
     assert_eq!(rows.len(), 1);
     for row in rows {
@@ -336,28 +316,26 @@ fn time() {
 
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn inet() {
     let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_inet \
                (my_inet_v4 inet PRIMARY KEY, my_inet_v6 inet)";
-    let session = setup(cql).expect("setup");
+    let mut session = setup(cql).expect("setup");
 
     let my_inet_v4 = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
     let my_inet_v6 = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
-    let values: Vec<Value> = vec![my_inet_v4.clone().into(), my_inet_v6.clone().into()];
+    let values = query_values!(my_inet_v4.clone(), my_inet_v6.clone());
 
-    let cql = "INSERT INTO cdrs_test.test_inet (my_inet_v4, my_inet_v6) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
+    let query = "INSERT INTO cdrs_test.test_inet (my_inet_v4, my_inet_v6) VALUES (?, ?)";
+    session.query_with_values(query, values)
+           .expect("insert inet error");
 
-    let cql = "SELECT * FROM cdrs_test.test_inet";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
-                      .expect("query")
+    let query = "SELECT * FROM cdrs_test.test_inet";
+    let rows = session.query(query)
+                      .expect("query inet error")
                       .get_body()
-                      .expect("get body")
+                      .expect("get body with inet error")
                       .into_rows()
-                      .expect("into rows");
+                      .expect("converting body with inet into rows error");
 
     assert_eq!(rows.len(), 1);
     for row in rows {
diff --git a/tests/simple_connect.rs b/tests/simple_connect.rs
deleted file mode 100644
index e0385e7..0000000
--- a/tests/simple_connect.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-
-extern crate cdrs;
-
-use cdrs::client::CDRS;
-use cdrs::query::QueryBuilder;
-use cdrs::authenticators::NoneAuthenticator;
-use cdrs::compression::Compression;
-use cdrs::consistency::Consistency;
-use cdrs::transport::TransportTcp;
-// default credentials
-const _ADDR: &'static str = "127.0.0.1:9042";
-
-
-
-#[test] #[ignore]
-#[cfg(not(feature = "appveyor"))]
-fn connect_to_cassandra() {
-    const _ADDR: &'static str = "127.0.0.1:9042";
-    let authenticator = NoneAuthenticator;
-    let tcp_transport = TransportTcp::new(_ADDR);
-    assert_eq!(tcp_transport.is_ok(), true);
-
-    let client = CDRS::new(tcp_transport.unwrap(), authenticator);
-    let session = client.start(Compression::None).unwrap();
-
-    let select_peers = "SELECT peer,data_center,rack,tokens,rpc_address,release_version FROM \
-                        system.peers";
-    let with_tracing = false;
-    let with_warnings = false;
-
-
-    let select_peers_query = QueryBuilder::new(select_peers)
-        .consistency(Consistency::One)
-        .finalize();
-
-    let select_peers_query_result = session.query(select_peers_query, with_tracing, with_warnings);
-
-    assert_eq!(select_peers_query_result.is_ok(), true);
-
-
-    match select_peers_query_result {
-        Ok(ref res) => println!("peers Selected: {:?}", res.get_body()),
-        Err(ref err) => println!("Error occured: {:?}", err),
-    }
-
-
-
-}
diff --git a/tests/tuple_types.rs b/tests/tuple_types.rs
index 4ca3200..3c1b57f 100644
--- a/tests/tuple_types.rs
+++ b/tests/tuple_types.rs
@@ -1,3 +1,4 @@
+#[macro_use]
 extern crate cdrs;
 extern crate regex;
 extern crate time;
@@ -9,178 +10,171 @@ use common::*;
 
 use uuid::Uuid;
 use time::Timespec;
-use cdrs::query::QueryBuilder;
+use cdrs::query::QueryExecutor;
 use cdrs::types::{IntoRustByIndex, IntoRustByName};
 use cdrs::types::value::{Bytes, Value};
 use cdrs::types::tuple::Tuple;
 use cdrs::types::blob::Blob;
 use cdrs::error::Result;
-use cdrs::IntoBytes;
+use cdrs::frame::IntoBytes;
 
 use std::str::FromStr;
 
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn simple_tuple() {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.simple_tuple \
-               (my_tuple tuple<text, int> PRIMARY KEY)";
-    let session = setup(cql).expect("setup");
-
-    #[derive(Debug, Clone, PartialEq)]
-    struct MyTuple {
-        pub my_text: String,
-        pub my_int: i32,
+  let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.simple_tuple \
+             (my_tuple tuple<text, int> PRIMARY KEY)";
+  let mut session = setup(cql).expect("setup");
+
+  #[derive(Debug, Clone, PartialEq)]
+  struct MyTuple {
+    pub my_text: String,
+    pub my_int: i32,
+  }
+
+  impl MyTuple {
+    pub fn try_from(tuple: Tuple) -> Result<MyTuple> {
+      let my_text: String = tuple.get_r_by_index(0)?;
+      let my_int: i32 = tuple.get_r_by_index(1)?;
+      Ok(MyTuple { my_text: my_text,
+                   my_int: my_int, })
     }
-
-    impl MyTuple {
-        pub fn try_from(tuple: Tuple) -> Result<MyTuple> {
-            let my_text: String = tuple.get_r_by_index(0)?;
-            let my_int: i32 = tuple.get_r_by_index(1)?;
-            Ok(MyTuple { my_text: my_text,
-                         my_int: my_int, })
-        }
-    }
-
-    impl Into<Bytes> for MyTuple {
-        fn into(self) -> Bytes {
-            let mut bytes = Vec::new();
-            let val_bytes: Bytes = self.my_text.into();
-            bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
-            let val_bytes: Bytes = self.my_int.into();
-            bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
-            Bytes::new(bytes)
-        }
-    }
-
-    let my_tuple = MyTuple { my_text: "my_text".to_string(),
-                             my_int: 0, };
-    let values: Vec<Value> = vec![my_tuple.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.simple_tuple \
-               (my_tuple) VALUES (?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.simple_tuple";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
-                      .expect("query")
-                      .get_body()
-                      .expect("get body")
-                      .into_rows()
-                      .expect("into rows");
-
-    assert_eq!(rows.len(), 1);
-    for row in rows {
-        let my_tuple_row: Tuple = row.get_r_by_name("my_tuple").expect("my_tuple");
-        let my_tuple_row = MyTuple::try_from(my_tuple_row).expect("my_tuple as rust");
-        assert_eq!(my_tuple_row, my_tuple);
+  }
+
+  impl Into<Bytes> for MyTuple {
+    fn into(self) -> Bytes {
+      let mut bytes = Vec::new();
+      let val_bytes: Bytes = self.my_text.into();
+      bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
+      let val_bytes: Bytes = self.my_int.into();
+      bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
+      Bytes::new(bytes)
     }
+  }
+
+  let my_tuple = MyTuple { my_text: "my_text".to_string(),
+                           my_int: 0, };
+  let values = query_values!(my_tuple.clone());
+
+  let cql = "INSERT INTO cdrs_test.simple_tuple \
+             (my_tuple) VALUES (?)";
+  session.query_with_values(cql, values).expect("insert");
+
+  let cql = "SELECT * FROM cdrs_test.simple_tuple";
+  let rows = session.query(cql)
+                    .expect("query")
+                    .get_body()
+                    .expect("get body")
+                    .into_rows()
+                    .expect("into rows");
+
+  assert_eq!(rows.len(), 1);
+  for row in rows {
+    let my_tuple_row: Tuple = row.get_r_by_name("my_tuple").expect("my_tuple");
+    let my_tuple_row = MyTuple::try_from(my_tuple_row).expect("my_tuple as rust");
+    assert_eq!(my_tuple_row, my_tuple);
+  }
 }
 
 #[test]
 #[ignore]
-#[cfg(not(feature = "appveyor"))]
 fn nested_tuples() {
-    let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_nested_tuples \
-               (my_key int PRIMARY KEY, \
-               my_outer_tuple tuple<uuid, blob, tuple<text, int, timestamp>>)";
-    let session = setup(cql).expect("setup");
-
-    #[derive(Debug, Clone, PartialEq)]
-    struct MyInnerTuple {
-        pub my_text: String,
-        pub my_int: i32,
-        pub my_timestamp: Timespec,
-    }
-
-    impl MyInnerTuple {
-        pub fn try_from(tuple: Tuple) -> Result<MyInnerTuple> {
-            let my_text: String = tuple.get_r_by_index(0)?;
-            let my_int: i32 = tuple.get_r_by_index(1)?;
-            let my_timestamp: Timespec = tuple.get_r_by_index(2)?;
-            Ok(MyInnerTuple { my_text: my_text,
-                              my_int: my_int,
-                              my_timestamp: my_timestamp, })
-        }
+  let cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_nested_tuples \
+             (my_key int PRIMARY KEY, \
+             my_outer_tuple tuple<uuid, blob, tuple<text, int, timestamp>>)";
+  let mut session = setup(cql).expect("setup");
+
+  #[derive(Debug, Clone, PartialEq)]
+  struct MyInnerTuple {
+    pub my_text: String,
+    pub my_int: i32,
+    pub my_timestamp: Timespec,
+  }
+
+  impl MyInnerTuple {
+    pub fn try_from(tuple: Tuple) -> Result<MyInnerTuple> {
+      let my_text: String = tuple.get_r_by_index(0)?;
+      let my_int: i32 = tuple.get_r_by_index(1)?;
+      let my_timestamp: Timespec = tuple.get_r_by_index(2)?;
+      Ok(MyInnerTuple { my_text: my_text,
+                        my_int: my_int,
+                        my_timestamp: my_timestamp, })
     }
-
-    impl Into<Bytes> for MyInnerTuple {
-        fn into(self) -> Bytes {
-            let mut bytes = Vec::new();
-            let val_bytes: Bytes = self.my_text.into();
-            bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
-            let val_bytes: Bytes = self.my_int.into();
-            bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
-            let val_bytes: Bytes = self.my_timestamp.into();
-            bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
-            Bytes::new(bytes)
-        }
-    }
-
-    #[derive(Debug, Clone, PartialEq)]
-    struct MyOuterTuple {
-        pub my_uuid: Uuid,
-        pub my_blob: Vec<u8>,
-        pub my_inner_tuple: MyInnerTuple,
+  }
+
+  impl Into<Bytes> for MyInnerTuple {
+    fn into(self) -> Bytes {
+      let mut bytes = Vec::new();
+      let val_bytes: Bytes = self.my_text.into();
+      bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
+      let val_bytes: Bytes = self.my_int.into();
+      bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
+      let val_bytes: Bytes = self.my_timestamp.into();
+      bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
+      Bytes::new(bytes)
     }
-
-    impl MyOuterTuple {
-        pub fn try_from(tuple: Tuple) -> Result<MyOuterTuple> {
-            let my_uuid: Uuid = tuple.get_r_by_index(0)?;
-            let my_blob: Blob = tuple.get_r_by_index(1)?;
-            let my_inner_tuple: Tuple = tuple.get_r_by_index(2)?;
-            let my_inner_tuple = MyInnerTuple::try_from(my_inner_tuple).expect("from tuple");
-            Ok(MyOuterTuple { my_uuid: my_uuid,
-                              my_blob: my_blob.into_vec(),
-                              my_inner_tuple: my_inner_tuple, })
-        }
+  }
+
+  #[derive(Debug, Clone, PartialEq)]
+  struct MyOuterTuple {
+    pub my_uuid: Uuid,
+    pub my_blob: Vec<u8>,
+    pub my_inner_tuple: MyInnerTuple,
+  }
+
+  impl MyOuterTuple {
+    pub fn try_from(tuple: Tuple) -> Result<MyOuterTuple> {
+      let my_uuid: Uuid = tuple.get_r_by_index(0)?;
+      let my_blob: Blob = tuple.get_r_by_index(1)?;
+      let my_inner_tuple: Tuple = tuple.get_r_by_index(2)?;
+      let my_inner_tuple = MyInnerTuple::try_from(my_inner_tuple).expect("from tuple");
+      Ok(MyOuterTuple { my_uuid: my_uuid,
+                        my_blob: my_blob.into_vec(),
+                        my_inner_tuple: my_inner_tuple, })
     }
-
-    impl Into<Bytes> for MyOuterTuple {
-        fn into(self) -> Bytes {
-            let mut bytes = Vec::new();
-            let val_bytes: Bytes = self.my_uuid.into();
-            bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
-            let val_bytes: Bytes = Bytes::new(self.my_blob);
-            bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
-            let val_bytes: Bytes = self.my_inner_tuple.into();
-            bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
-            Bytes::new(bytes)
-        }
-    }
-
-    let my_uuid = Uuid::from_str("bb16106a-10bc-4a07-baa3-126ffe208c43").unwrap();
-    let my_blob: Vec<u8> = vec![0, 1, 2, 4, 8, 16, 32, 64, 128, 255];
-    let my_inner_tuple = MyInnerTuple { my_text: "my_text".to_string(),
-                                        my_int: 1_000,
-                                        my_timestamp: Timespec { sec: 1,
-                                                                 nsec: 999_000_000, }, };
-    let my_outer_tuple = MyOuterTuple { my_uuid: my_uuid,
-                                        my_blob: my_blob,
-                                        my_inner_tuple: my_inner_tuple, };
-    let values: Vec<Value> = vec![0i32.into(), my_outer_tuple.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_nested_tuples \
-               (my_key, my_outer_tuple) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_nested_tuples";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session.query(query, false, false)
-                      .expect("query")
-                      .get_body()
-                      .expect("get body")
-                      .into_rows()
-                      .expect("into rows");
-
-    assert_eq!(rows.len(), 1);
-    for row in rows {
-        let my_outer_tuple_row: Tuple =
-            row.get_r_by_name("my_outer_tuple").expect("my_outer_tuple");
-        let my_outer_tuple_row = MyOuterTuple::try_from(my_outer_tuple_row).expect("from tuple");
-        assert_eq!(my_outer_tuple_row, my_outer_tuple);
+  }
+
+  impl Into<Bytes> for MyOuterTuple {
+    fn into(self) -> Bytes {
+      let mut bytes = Vec::new();
+      let val_bytes: Bytes = self.my_uuid.into();
+      bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
+      let val_bytes: Bytes = Bytes::new(self.my_blob);
+      bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
+      let val_bytes: Bytes = self.my_inner_tuple.into();
+      bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
+      Bytes::new(bytes)
     }
+  }
+
+  let my_uuid = Uuid::from_str("bb16106a-10bc-4a07-baa3-126ffe208c43").unwrap();
+  let my_blob: Vec<u8> = vec![0, 1, 2, 4, 8, 16, 32, 64, 128, 255];
+  let my_inner_tuple = MyInnerTuple { my_text: "my_text".to_string(),
+                                      my_int: 1_000,
+                                      my_timestamp: Timespec { sec: 1,
+                                                               nsec: 999_000_000, }, };
+  let my_outer_tuple = MyOuterTuple { my_uuid: my_uuid,
+                                      my_blob: my_blob,
+                                      my_inner_tuple: my_inner_tuple, };
+  let values = query_values!(0i32, my_outer_tuple.clone());
+
+  let cql = "INSERT INTO cdrs_test.test_nested_tuples \
+             (my_key, my_outer_tuple) VALUES (?, ?)";
+  session.query_with_values(cql, values).expect("insert");
+
+  let cql = "SELECT * FROM cdrs_test.test_nested_tuples";
+  let rows = session.query(cql)
+                    .expect("query")
+                    .get_body()
+                    .expect("get body")
+                    .into_rows()
+                    .expect("into rows");
+
+  assert_eq!(rows.len(), 1);
+  for row in rows {
+    let my_outer_tuple_row: Tuple = row.get_r_by_name("my_outer_tuple").expect("my_outer_tuple");
+    let my_outer_tuple_row = MyOuterTuple::try_from(my_outer_tuple_row).expect("from tuple");
+    assert_eq!(my_outer_tuple_row, my_outer_tuple);
+  }
 }
diff --git a/tests/user_defined_types.rs b/tests/user_defined_types.rs
index 0d3d57a..a5097ef 100644
--- a/tests/user_defined_types.rs
+++ b/tests/user_defined_types.rs
@@ -1,3 +1,4 @@
+#[macro_use]
 extern crate cdrs;
 #[macro_use]
 extern crate maplit;
@@ -9,245 +10,222 @@ mod common;
 
 use common::*;
 
-use cdrs::query::QueryBuilder;
+use cdrs::query::QueryExecutor;
 use cdrs::types::{AsRust, IntoRustByName};
 use cdrs::types::value::{Bytes, Value};
 use cdrs::types::udt::UDT;
 use cdrs::types::map::Map;
 use cdrs::error::Result;
-use cdrs::IntoBytes;
+use cdrs::frame::IntoBytes;
 use time::Timespec;
 
 use std::collections::HashMap;
 
-#[test] #[ignore]
-#[cfg(not(feature = "appveyor"))]
+#[test]
+#[ignore]
 fn simple_udt() {
-    let create_type_cql = "CREATE TYPE IF NOT EXISTS cdrs_test.simple_udt (my_text text)";
-    let create_table_cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_simple_udt \
-                            (my_key int PRIMARY KEY, my_udt simple_udt)";
-    let session = setup_multiple(&[create_type_cql, create_table_cql]).expect("setup");
-
-    #[derive(Debug, Clone, PartialEq)]
-    struct MyUdt {
-        pub my_text: String,
-    }
-
-    impl MyUdt {
-        pub fn try_from(udt: UDT) -> Result<MyUdt> {
-            let my_text: String = udt.get_r_by_name("my_text")?;
-            Ok(MyUdt { my_text: my_text })
-        }
-    }
-
-    impl Into<Bytes> for MyUdt {
-        fn into(self) -> Bytes {
-            let mut bytes = Vec::new();
-            let val_bytes: Bytes = self.my_text.into();
-            bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
-            Bytes::new(bytes)
-        }
-    }
-
-    let my_udt = MyUdt {
-        my_text: "my_text".to_string(),
-    };
-    let values: Vec<Value> = vec![0i32.into(), my_udt.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_simple_udt \
-               (my_key, my_udt) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_simple_udt";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session
-        .query(query, false, false)
-        .expect("query")
-        .get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows");
-
-    assert_eq!(rows.len(), 1);
-    for row in rows {
-        let my_udt_row: UDT = row.get_r_by_name("my_udt").expect("my_udt");
-        let my_udt_row = MyUdt::try_from(my_udt_row).expect("from udt");
-        assert_eq!(my_udt_row, my_udt);
-    }
+  let create_type_cql = "CREATE TYPE IF NOT EXISTS cdrs_test.simple_udt (my_text text)";
+  let create_table_cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_simple_udt \
+                          (my_key int PRIMARY KEY, my_udt simple_udt)";
+  let mut session = setup_multiple(&[create_type_cql, create_table_cql]).expect("setup");
+
+  #[derive(Debug, Clone, PartialEq)]
+  struct MyUdt {
+    pub my_text: String,
+  }
+
+  impl MyUdt {
+    pub fn try_from(udt: UDT) -> Result<MyUdt> {
+      let my_text: String = udt.get_r_by_name("my_text")?;
+      Ok(MyUdt { my_text: my_text })
+    }
+  }
+
+  impl Into<Bytes> for MyUdt {
+    fn into(self) -> Bytes {
+      let mut bytes = Vec::new();
+      let val_bytes: Bytes = self.my_text.into();
+      bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
+      Bytes::new(bytes)
+    }
+  }
+
+  let my_udt = MyUdt { my_text: "my_text".to_string(), };
+  let values = query_values!(0i32, my_udt.clone());
+
+  let cql = "INSERT INTO cdrs_test.test_simple_udt \
+             (my_key, my_udt) VALUES (?, ?)";
+  session.query_with_values(cql, values).expect("insert");
+
+  let cql = "SELECT * FROM cdrs_test.test_simple_udt";
+  let rows = session.query(cql)
+                    .expect("query")
+                    .get_body()
+                    .expect("get body")
+                    .into_rows()
+                    .expect("into rows");
+
+  assert_eq!(rows.len(), 1);
+  for row in rows {
+    let my_udt_row: UDT = row.get_r_by_name("my_udt").expect("my_udt");
+    let my_udt_row = MyUdt::try_from(my_udt_row).expect("from udt");
+    assert_eq!(my_udt_row, my_udt);
+  }
 }
 
-#[test] #[ignore]
-#[cfg(not(feature = "appveyor"))]
+#[test]
+#[ignore]
 fn nested_udt() {
-    let create_type1_cql = "CREATE TYPE IF NOT EXISTS cdrs_test.nested_inner_udt (my_text text)";
-    let create_type2_cql = "CREATE TYPE IF NOT EXISTS cdrs_test.nested_outer_udt \
-                            (my_inner_udt frozen<nested_inner_udt>)";
-    let create_table_cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_nested_udt \
-                            (my_key int PRIMARY KEY, my_outer_udt nested_outer_udt)";
-    let session =
-        setup_multiple(&[create_type1_cql, create_type2_cql, create_table_cql]).expect("setup");
-
-    #[derive(Debug, Clone, PartialEq)]
-    struct MyInnerUdt {
-        pub my_text: String,
-    }
-
-    impl MyInnerUdt {
-        pub fn try_from(udt: UDT) -> Result<MyInnerUdt> {
-            let my_text: String = udt.get_r_by_name("my_text")?;
-            Ok(MyInnerUdt { my_text: my_text })
-        }
-    }
-
-    impl Into<Bytes> for MyInnerUdt {
-        fn into(self) -> Bytes {
-            let mut bytes = Vec::new();
-            let val_bytes: Bytes = self.my_text.into();
-            bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
-            Bytes::new(bytes)
-        }
-    }
-
-    #[derive(Debug, Clone, PartialEq)]
-    struct MyOuterUdt {
-        pub my_inner_udt: MyInnerUdt,
-    }
-
-    impl MyOuterUdt {
-        pub fn try_from(udt: UDT) -> Result<MyOuterUdt> {
-            let my_inner_udt: UDT = udt.get_r_by_name("my_inner_udt")?;
-            let my_inner_udt = MyInnerUdt::try_from(my_inner_udt).expect("from udt");
-            Ok(MyOuterUdt {
-                   my_inner_udt: my_inner_udt,
-               })
-        }
-    }
-
-    impl Into<Bytes> for MyOuterUdt {
-        fn into(self) -> Bytes {
-            let mut bytes = Vec::new();
-            let val_bytes: Bytes = self.my_inner_udt.into();
-            bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
-            Bytes::new(bytes)
-        }
-    }
-
-    let my_inner_udt = MyInnerUdt {
-        my_text: "my_text".to_string(),
-    };
-    let my_outer_udt = MyOuterUdt {
-        my_inner_udt: my_inner_udt,
-    };
-    let values: Vec<Value> = vec![0i32.into(), my_outer_udt.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_nested_udt \
-               (my_key, my_outer_udt) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "SELECT * FROM cdrs_test.test_nested_udt";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session
-        .query(query, false, false)
-        .expect("query")
-        .get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows");
-
-    assert_eq!(rows.len(), 1);
-    for row in rows {
-        let my_outer_udt_row: UDT = row.get_r_by_name("my_outer_udt").expect("my_outer_udt");
-        let my_outer_udt_row = MyOuterUdt::try_from(my_outer_udt_row).expect("from udt");
-        assert_eq!(my_outer_udt_row, my_outer_udt);
-    }
+  let create_type1_cql = "CREATE TYPE IF NOT EXISTS cdrs_test.nested_inner_udt (my_text text)";
+  let create_type2_cql = "CREATE TYPE IF NOT EXISTS cdrs_test.nested_outer_udt \
+                          (my_inner_udt frozen<nested_inner_udt>)";
+  let create_table_cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_nested_udt \
+                          (my_key int PRIMARY KEY, my_outer_udt nested_outer_udt)";
+  let mut session =
+    setup_multiple(&[create_type1_cql, create_type2_cql, create_table_cql]).expect("setup");
+
+  #[derive(Debug, Clone, PartialEq)]
+  struct MyInnerUdt {
+    pub my_text: String,
+  }
+
+  impl MyInnerUdt {
+    pub fn try_from(udt: UDT) -> Result<MyInnerUdt> {
+      let my_text: String = udt.get_r_by_name("my_text")?;
+      Ok(MyInnerUdt { my_text: my_text })
+    }
+  }
+
+  impl Into<Bytes> for MyInnerUdt {
+    fn into(self) -> Bytes {
+      let mut bytes = Vec::new();
+      let val_bytes: Bytes = self.my_text.into();
+      bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
+      Bytes::new(bytes)
+    }
+  }
+
+  #[derive(Debug, Clone, PartialEq)]
+  struct MyOuterUdt {
+    pub my_inner_udt: MyInnerUdt,
+  }
+
+  impl MyOuterUdt {
+    pub fn try_from(udt: UDT) -> Result<MyOuterUdt> {
+      let my_inner_udt: UDT = udt.get_r_by_name("my_inner_udt")?;
+      let my_inner_udt = MyInnerUdt::try_from(my_inner_udt).expect("from udt");
+      Ok(MyOuterUdt { my_inner_udt: my_inner_udt, })
+    }
+  }
+
+  impl Into<Bytes> for MyOuterUdt {
+    fn into(self) -> Bytes {
+      let mut bytes = Vec::new();
+      let val_bytes: Bytes = self.my_inner_udt.into();
+      bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
+      Bytes::new(bytes)
+    }
+  }
+
+  let my_inner_udt = MyInnerUdt { my_text: "my_text".to_string(), };
+  let my_outer_udt = MyOuterUdt { my_inner_udt: my_inner_udt, };
+  let values = query_values!(0i32, my_outer_udt.clone());
+
+  let cql = "INSERT INTO cdrs_test.test_nested_udt \
+             (my_key, my_outer_udt) VALUES (?, ?)";
+  session.query_with_values(cql, values).expect("insert");
+
+  let cql = "SELECT * FROM cdrs_test.test_nested_udt";
+  let rows = session.query(cql)
+                    .expect("query")
+                    .get_body()
+                    .expect("get body")
+                    .into_rows()
+                    .expect("into rows");
+
+  assert_eq!(rows.len(), 1);
+  for row in rows {
+    let my_outer_udt_row: UDT = row.get_r_by_name("my_outer_udt").expect("my_outer_udt");
+    let my_outer_udt_row = MyOuterUdt::try_from(my_outer_udt_row).expect("from udt");
+    assert_eq!(my_outer_udt_row, my_outer_udt);
+  }
 }
 
-#[test] #[ignore]
-#[cfg(not(feature = "appveyor"))]
+#[test]
+#[ignore]
 fn alter_udt_add() {
-    let drop_table_cql = "DROP TABLE IF EXISTS cdrs_test.test_alter_udt_add";
-    let drop_type_cql = "DROP TYPE IF EXISTS cdrs_test.alter_udt_add_udt";
-    let create_type_cql = "CREATE TYPE cdrs_test.alter_udt_add_udt (my_text text)";
-    let create_table_cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_alter_udt_add \
-                            (my_key int PRIMARY KEY, my_map frozen<map<text, alter_udt_add_udt>>)";
-    let session = setup_multiple(&[drop_table_cql,
-                                       drop_type_cql,
-                                       create_type_cql,
-                                       create_table_cql])
-        .expect("setup");
-
-    #[derive(Debug, Clone, PartialEq)]
-    struct MyUdtA {
-        pub my_text: String,
-    }
-
-    impl Into<Bytes> for MyUdtA {
-        fn into(self) -> Bytes {
-            let mut bytes = Vec::new();
-            let val_bytes: Bytes = self.my_text.into();
-            bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
-            Bytes::new(bytes)
-        }
-    }
-
-    #[derive(Debug, Clone, PartialEq)]
-    struct MyUdtB {
-        pub my_text: String,
-        pub my_timestamp: Option<Timespec>,
-    }
-
-    impl MyUdtB {
-        pub fn try_from(udt: UDT) -> Result<MyUdtB> {
-            let my_text: String = udt.get_r_by_name("my_text")?;
-            let my_timestamp: Option<Timespec> = udt.get_by_name("my_timestamp")?;
-            Ok(MyUdtB {
-                   my_text: my_text,
-                   my_timestamp: my_timestamp,
-               })
-        }
-    }
-
-    let my_udt_a = MyUdtA {
-        my_text: "my_text".to_string(),
-    };
-    let my_map_a = hashmap! { "1" => my_udt_a.clone() };
-    let values: Vec<Value> = vec![0i32.into(), my_map_a.clone().into()];
-
-    let cql = "INSERT INTO cdrs_test.test_alter_udt_add \
-               (my_key, my_map) VALUES (?, ?)";
-    let query = QueryBuilder::new(cql).values(values).finalize();
-    session.query(query, false, false).expect("insert");
-
-    let cql = "ALTER TYPE cdrs_test.alter_udt_add_udt ADD my_timestamp timestamp";
-    let query = QueryBuilder::new(cql).finalize();
-    session.query(query, false, false).expect("alter type");
-
-    let my_udt_b = MyUdtB {
-        my_text: my_udt_a.my_text,
-        my_timestamp: None,
-    };
-
-    let cql = "SELECT * FROM cdrs_test.test_alter_udt_add";
-    let query = QueryBuilder::new(cql).finalize();
-    let rows = session
-        .query(query, false, false)
-        .expect("query")
-        .get_body()
-        .expect("get body")
-        .into_rows()
-        .expect("into rows");
-
-    assert_eq!(rows.len(), 1);
-    for row in rows {
-        let my_map_row: Map = row.get_r_by_name("my_map").expect("my_map");
-        let my_map_row: HashMap<String, UDT> = my_map_row.as_r_rust().expect("my_map as rust");
-
-        for (key, my_udt_row) in my_map_row {
-            let my_udt_row = MyUdtB::try_from(my_udt_row).expect("from udt");
-            assert_eq!(key, "1");
-            assert_eq!(my_udt_row, my_udt_b);
-        }
-    }
+  let drop_table_cql = "DROP TABLE IF EXISTS cdrs_test.test_alter_udt_add";
+  let drop_type_cql = "DROP TYPE IF EXISTS cdrs_test.alter_udt_add_udt";
+  let create_type_cql = "CREATE TYPE cdrs_test.alter_udt_add_udt (my_text text)";
+  let create_table_cql = "CREATE TABLE IF NOT EXISTS cdrs_test.test_alter_udt_add \
+                          (my_key int PRIMARY KEY, my_map frozen<map<text, alter_udt_add_udt>>)";
+  let mut session = setup_multiple(&[
+    drop_table_cql,
+    drop_type_cql,
+    create_type_cql,
+    create_table_cql,
+  ]).expect("setup");
+
+  #[derive(Debug, Clone, PartialEq)]
+  struct MyUdtA {
+    pub my_text: String,
+  }
+
+  impl Into<Bytes> for MyUdtA {
+    fn into(self) -> Bytes {
+      let mut bytes = Vec::new();
+      let val_bytes: Bytes = self.my_text.into();
+      bytes.extend_from_slice(Value::new_normal(val_bytes).into_cbytes().as_slice());
+      Bytes::new(bytes)
+    }
+  }
+
+  #[derive(Debug, Clone, PartialEq)]
+  struct MyUdtB {
+    pub my_text: String,
+    pub my_timestamp: Option<Timespec>,
+  }
+
+  impl MyUdtB {
+    pub fn try_from(udt: UDT) -> Result<MyUdtB> {
+      let my_text: String = udt.get_r_by_name("my_text")?;
+      let my_timestamp: Option<Timespec> = udt.get_by_name("my_timestamp")?;
+      Ok(MyUdtB { my_text: my_text,
+                  my_timestamp: my_timestamp, })
+    }
+  }
+
+  let my_udt_a = MyUdtA { my_text: "my_text".to_string(), };
+  let my_map_a = hashmap! { "1" => my_udt_a.clone() };
+  let values = query_values!(0i32, my_map_a.clone());
+
+  let cql = "INSERT INTO cdrs_test.test_alter_udt_add \
+             (my_key, my_map) VALUES (?, ?)";
+  session.query_with_values(cql, values).expect("insert");
+
+  let cql = "ALTER TYPE cdrs_test.alter_udt_add_udt ADD my_timestamp timestamp";
+  session.query(cql).expect("alter type");
+
+  let my_udt_b = MyUdtB { my_text: my_udt_a.my_text,
+                          my_timestamp: None, };
+
+  let cql = "SELECT * FROM cdrs_test.test_alter_udt_add";
+  let rows = session.query(cql)
+                    .expect("query")
+                    .get_body()
+                    .expect("get body")
+                    .into_rows()
+                    .expect("into rows");
+
+  assert_eq!(rows.len(), 1);
+  for row in rows {
+    let my_map_row: Map = row.get_r_by_name("my_map").expect("my_map");
+    let my_map_row: HashMap<String, UDT> = my_map_row.as_r_rust().expect("my_map as rust");
+
+    for (key, my_udt_row) in my_map_row {
+      let my_udt_row = MyUdtB::try_from(my_udt_row).expect("from udt");
+      assert_eq!(key, "1");
+      assert_eq!(my_udt_row, my_udt_b);
+    }
+  }
 }