From a7d5a9f6c21a0ccb7b3d86694ffeff8d0ee14d2a Mon Sep 17 00:00:00 2001
From: Artem Zinnatullin <artem.zinnatullin@gmail.com>
Date: Sun, 21 Jun 2015 18:43:39 +0300
Subject: [PATCH] New packages naming convention

---
 build.gradle                                       |   4 +-
 settings.gradle                                    |   9 +-
 .../storio/operation/PreparedOperation.java        |  38 --
 .../operation/group/GroupOperationResults.java     |  75 ----
 .../operation/group/PreparedGroupOperation.java    |  82 ----
 .../internal/MapSomethingToExecuteAsBlocking.java  |  41 --
 .../internal/OnSubscribeExecuteAsBlocking.java     |  46 --
 .../storio/operations/PreparedOperation.java       |  38 ++
 .../operations/group/GroupOperationResults.java    |  75 ++++
 .../operations/group/PreparedGroupOperation.java   |  82 ++++
 .../internal/MapSomethingToExecuteAsBlocking.java  |  41 ++
 .../internal/OnSubscribeExecuteAsBlocking.java     |  46 ++
 .../operation/group/GroupOperationResultsTest.java |  32 --
 .../storio/operation/group/GroupOperationStub.java |  75 ----
 .../MapSomethingToExecuteAsBlockingTest.java       |  37 --
 .../internal/OnSubscribeExecuteAsBlockingTest.java |  36 --
 .../group/GroupOperationResultsTest.java           |  32 ++
 .../operations/group/GroupOperationStub.java       |  75 ++++
 .../MapSomethingToExecuteAsBlockingTest.java       |  37 ++
 .../internal/OnSubscribeExecuteAsBlockingTest.java |  36 ++
 .../storio/content_resolver/impl/BaseTest.java     |  10 +-
 .../storio/content_resolver/impl/DeleteTest.java   |   2 +-
 .../storio/content_resolver/impl/InsertTest.java   |   4 +-
 .../storio/content_resolver/impl/QueryTest.java    |   4 +-
 .../storio/content_resolver/impl/TweetMeta.java    |  20 +-
 .../storio/content_resolver/impl/UpdateTest.java   |   4 +-
 .../storio/content_resolver/impl/UserMeta.java     |  20 +-
 .../ContentResolverTypeMapping.java                |   6 +-
 .../contentresolver/StorIOContentResolver.java     |  14 +-
 .../impl/DefaultStorIOContentResolver.java         |   8 +-
 .../operation/delete/DefaultDeleteResolver.java    |  36 --
 .../operation/delete/DeleteResolver.java           |  21 -
 .../operation/delete/DeleteResult.java             |  98 ----
 .../operation/delete/DeleteResults.java            |  81 ----
 .../operation/delete/PreparedDelete.java           |  80 ----
 .../operation/delete/PreparedDeleteByQuery.java    | 146 ------
 .../delete/PreparedDeleteCollectionOfObjects.java  | 187 --------
 .../operation/delete/PreparedDeleteObject.java     | 155 -------
 .../operation/get/DefaultGetResolver.java          |  22 -
 .../contentresolver/operation/get/GetResolver.java |  40 --
 .../contentresolver/operation/get/PreparedGet.java |  56 ---
 .../operation/get/PreparedGetCursor.java           | 172 -------
 .../operation/get/PreparedGetListOfObjects.java    | 221 ---------
 .../operation/put/DefaultPutResolver.java          |  83 ----
 .../contentresolver/operation/put/PreparedPut.java |  83 ----
 .../put/PreparedPutCollectionOfObjects.java        | 182 --------
 .../operation/put/PreparedPutContentValues.java    | 151 -------
 .../put/PreparedPutContentValuesIterable.java      | 154 -------
 .../operation/put/PreparedPutObject.java           | 148 ------
 .../contentresolver/operation/put/PutResolver.java |  25 --
 .../contentresolver/operation/put/PutResult.java   | 155 -------
 .../contentresolver/operation/put/PutResults.java  | 125 ------
 .../operations/delete/DefaultDeleteResolver.java   |  36 ++
 .../operations/delete/DeleteResolver.java          |  21 +
 .../operations/delete/DeleteResult.java            |  98 ++++
 .../operations/delete/DeleteResults.java           |  81 ++++
 .../operations/delete/PreparedDelete.java          |  80 ++++
 .../operations/delete/PreparedDeleteByQuery.java   | 146 ++++++
 .../delete/PreparedDeleteCollectionOfObjects.java  | 187 ++++++++
 .../operations/delete/PreparedDeleteObject.java    | 155 +++++++
 .../operations/get/DefaultGetResolver.java         |  22 +
 .../operations/get/GetResolver.java                |  40 ++
 .../operations/get/PreparedGet.java                |  56 +++
 .../operations/get/PreparedGetCursor.java          | 172 +++++++
 .../operations/get/PreparedGetListOfObjects.java   | 221 +++++++++
 .../operations/put/DefaultPutResolver.java         |  83 ++++
 .../operations/put/PreparedPut.java                |  83 ++++
 .../put/PreparedPutCollectionOfObjects.java        | 182 ++++++++
 .../operations/put/PreparedPutContentValues.java   | 151 +++++++
 .../put/PreparedPutContentValuesIterable.java      | 154 +++++++
 .../operations/put/PreparedPutObject.java          | 148 ++++++
 .../operations/put/PutResolver.java                |  25 ++
 .../contentresolver/operations/put/PutResult.java  | 155 +++++++
 .../contentresolver/operations/put/PutResults.java | 125 ++++++
 .../contentresolver/queries/DeleteQuery.java       | 219 +++++++++
 .../contentresolver/queries/InsertQuery.java       | 133 ++++++
 .../storio/contentresolver/queries/Query.java      | 308 +++++++++++++
 .../contentresolver/queries/UpdateQuery.java       | 217 +++++++++
 .../storio/contentresolver/query/DeleteQuery.java  | 219 ---------
 .../storio/contentresolver/query/InsertQuery.java  | 133 ------
 .../storio/contentresolver/query/Query.java        | 308 -------------
 .../storio/contentresolver/query/UpdateQuery.java  | 217 ---------
 .../ContentResolverTypeMappingTest.java            |   6 +-
 .../storio/contentresolver/design/ArticleMeta.java |  18 +-
 .../design/DeleteOperationDesignTest.java          |   6 +-
 .../design/DesignTestStorIOContentResolver.java    |   8 +-
 .../design/GetOperationDesignTest.java             |   4 +-
 .../design/PutOperationDesignTest.java             |  12 +-
 .../impl/DefaultStorIOContentResolverTest.java     |   6 +-
 .../delete/DefaultDeleteResolverTest.java          |  68 ---
 .../operation/delete/DeleteByQueryStub.java        |  89 ----
 .../operation/delete/DeleteObjectsStub.java        | 171 -------
 .../operation/delete/DeleteResultTest.java         |  53 ---
 .../operation/delete/DeleteResultsTest.java        |  31 --
 .../delete/PreparedDeleteByQueryTest.java          |  36 --
 .../PreparedDeleteCollectionOfObjectsTest.java     | 150 -------
 .../operation/delete/PreparedDeleteObjectTest.java | 143 ------
 .../contentresolver/operation/delete/TestItem.java |  15 -
 .../operation/get/DefaultGetResolverTest.java      |  61 ---
 .../operation/get/GetCursorStub.java               |  95 ----
 .../operation/get/GetObjectsStub.java              | 187 --------
 .../operation/get/PreparedGetCursorTest.java       |  42 --
 .../get/PreparedGetListOfObjectsTest.java          | 161 -------
 .../contentresolver/operation/get/TestItem.java    |  29 --
 .../operation/put/DefaultPutResolverTest.java      | 260 -----------
 .../put/PreparedPutCollectionOfObjectsTest.java    | 155 -------
 .../put/PreparedPutContentValuesIterableTest.java  |  38 --
 .../put/PreparedPutContentValuesTest.java          |  36 --
 .../operation/put/PreparedPutObjectTest.java       | 148 ------
 .../operation/put/PutContentValuesStub.java        | 132 ------
 .../operation/put/PutObjectsStub.java              | 173 -------
 .../contentresolver/operation/put/TestItem.java    |  19 -
 .../delete/DefaultDeleteResolverTest.java          |  68 +++
 .../operations/delete/DeleteByQueryStub.java       |  89 ++++
 .../operations/delete/DeleteObjectsStub.java       | 171 +++++++
 .../operations/delete/DeleteResultTest.java        |  53 +++
 .../operations/delete/DeleteResultsTest.java       |  31 ++
 .../delete/PreparedDeleteByQueryTest.java          |  36 ++
 .../PreparedDeleteCollectionOfObjectsTest.java     | 150 +++++++
 .../delete/PreparedDeleteObjectTest.java           | 143 ++++++
 .../operations/delete/TestItem.java                |  15 +
 .../operations/get/DefaultGetResolverTest.java     |  61 +++
 .../operations/get/GetCursorStub.java              |  95 ++++
 .../operations/get/GetObjectsStub.java             | 187 ++++++++
 .../operations/get/PreparedGetCursorTest.java      |  42 ++
 .../get/PreparedGetListOfObjectsTest.java          | 161 +++++++
 .../contentresolver/operations/get/TestItem.java   |  29 ++
 .../operations/put/DefaultPutResolverTest.java     | 260 +++++++++++
 .../put/PreparedPutCollectionOfObjectsTest.java    | 155 +++++++
 .../put/PreparedPutContentValuesIterableTest.java  |  38 ++
 .../put/PreparedPutContentValuesTest.java          |  36 ++
 .../operations/put/PreparedPutObjectTest.java      | 148 ++++++
 .../operations/put/PutContentValuesStub.java       | 132 ++++++
 .../operations/put/PutObjectsStub.java             | 173 +++++++
 .../contentresolver/operations/put/TestItem.java   |  19 +
 .../contentresolver/queries/DeleteQueryTest.java   |  77 ++++
 .../contentresolver/queries/InsertQueryTest.java   |  38 ++
 .../storio/contentresolver/queries/QueryTest.java  |  93 ++++
 .../contentresolver/queries/UpdateQueryTest.java   |  75 ++++
 .../contentresolver/query/DeleteQueryTest.java     |  77 ----
 .../contentresolver/query/InsertQueryTest.java     |  38 --
 .../storio/contentresolver/query/QueryTest.java    |  93 ----
 .../contentresolver/query/UpdateQueryTest.java     |  75 ----
 .../storio/contentresolver/test/BaseTest.java      |   2 +-
 .../contentresolver/test/ObserveChangesTest.java   |   4 +-
 .../storio/contentresolver/test/RxQueryTest.java   |   6 +-
 .../storio/sample/db/entity/Tweet.java             |   4 +-
 .../storio/sample/db/table/TweetTableMeta.java     |  20 +-
 .../storio/sample/provider/meta/TweetMeta.java     |  18 +-
 .../storio/sample/ui/fragment/TweetsFragment.java  |   2 +-
 storio-sqlite-annotation-processor/build.gradle    |  16 -
 .../gradle.properties                              |   3 -
 .../sqlite/processor/ProcessingException.java      |  31 --
 .../sqlite/processor/StorIOSQLiteProcessor.java    | 331 --------------
 .../storio/sqlite/processor/generate/Common.java   |  10 -
 .../generate/DeleteResolverGenerator.java          |  62 ---
 .../processor/generate/GetResolverGenerator.java   | 100 -----
 .../processor/generate/PutResolverGenerator.java   | 111 -----
 .../sqlite/processor/generate/QueryGenerator.java  |  63 ---
 .../sqlite/processor/introspection/JavaType.java   |  59 ---
 .../introspection/StorIOSQLiteColumnMeta.java      |  68 ---
 .../introspection/StorIOSQLiteTypeMeta.java        |  64 ---
 .../generate/DeleteResolverGeneratorTest.java      |  82 ----
 .../generate/GetResolverGeneratorTest.java         |  84 ----
 .../generate/PutResolverGeneratorTest.java         | 109 -----
 .../processor/generate/QueryGeneratorTest.java     |  91 ----
 .../processor/introspection/JavaTypeTest.java      | 116 -----
 storio-sqlite-annotation/build.gradle              |   6 -
 storio-sqlite-annotation/gradle.properties         |   3 -
 .../sqlite/annotation/StorIOSQLiteColumn.java      |  29 --
 .../storio/sqlite/annotation/StorIOSQLiteType.java |  22 -
 storio-sqlite-annotations-processor/build.gradle   |  16 +
 .../gradle.properties                              |   3 +
 .../annotations/processor/ProcessingException.java |  31 ++
 .../processor/StorIOSQLiteProcessor.java           | 331 ++++++++++++++
 .../annotations/processor/generate/Common.java     |  10 +
 .../generate/DeleteResolverGenerator.java          |  62 +++
 .../processor/generate/GetResolverGenerator.java   | 100 +++++
 .../processor/generate/PutResolverGenerator.java   | 111 +++++
 .../processor/generate/QueryGenerator.java         |  63 +++
 .../processor/introspection/JavaType.java          |  59 +++
 .../introspection/StorIOSQLiteColumnMeta.java      |  68 +++
 .../introspection/StorIOSQLiteTypeMeta.java        |  64 +++
 .../generate/DeleteResolverGeneratorTest.java      |  82 ++++
 .../generate/GetResolverGeneratorTest.java         |  84 ++++
 .../generate/PutResolverGeneratorTest.java         | 109 +++++
 .../processor/generate/QueryGeneratorTest.java     |  91 ++++
 .../processor/introspection/JavaTypeTest.java      | 116 +++++
 storio-sqlite-annotations/build.gradle             |   6 +
 storio-sqlite-annotations/gradle.properties        |   3 +
 .../sqlite/annotations/StorIOSQLiteColumn.java     |  29 ++
 .../sqlite/annotations/StorIOSQLiteType.java       |  22 +
 .../pushtorefresh/storio/sqlite/impl/BaseTest.java |   8 +-
 .../storio/sqlite/impl/DeleteTest.java             |   2 +-
 .../storio/sqlite/impl/QueryTest.java              |   8 +-
 .../storio/sqlite/impl/TweetTableMeta.java         |  18 +-
 .../storio/sqlite/impl/UpdateTest.java             |   4 +-
 .../storio/sqlite/impl/UserTableMeta.java          |  22 +-
 .../sqlite/impl/auto_parcel/AutoParcelTest.java    |   8 +-
 .../sqlite/impl/auto_parcel/BookTableMeta.java     |  18 +-
 .../storio/sqlite/SQLiteTypeMapping.java           |   6 +-
 .../pushtorefresh/storio/sqlite/StorIOSQLite.java  |  18 +-
 .../storio/sqlite/impl/DefaultStorIOSQLite.java    |  10 +-
 .../operation/delete/DefaultDeleteResolver.java    |  33 --
 .../sqlite/operation/delete/DeleteResolver.java    |  23 -
 .../sqlite/operation/delete/DeleteResult.java      |  98 ----
 .../sqlite/operation/delete/DeleteResults.java     |  90 ----
 .../sqlite/operation/delete/PreparedDelete.java    |  72 ---
 .../operation/delete/PreparedDeleteByQuery.java    | 131 ------
 .../delete/PreparedDeleteCollectionOfObjects.java  | 244 ----------
 .../operation/delete/PreparedDeleteObject.java     | 150 -------
 .../operation/execute/PreparedExecuteSQL.java      | 146 ------
 .../sqlite/operation/get/DefaultGetResolver.java   |  36 --
 .../storio/sqlite/operation/get/GetResolver.java   |  48 --
 .../storio/sqlite/operation/get/PreparedGet.java   |  74 ---
 .../sqlite/operation/get/PreparedGetCursor.java    | 224 ---------
 .../operation/get/PreparedGetListOfObjects.java    | 292 ------------
 .../sqlite/operation/put/DefaultPutResolver.java   |  95 ----
 .../storio/sqlite/operation/put/PreparedPut.java   |  94 ----
 .../put/PreparedPutCollectionOfObjects.java        | 236 ----------
 .../operation/put/PreparedPutContentValues.java    | 146 ------
 .../put/PreparedPutContentValuesIterable.java      | 211 ---------
 .../sqlite/operation/put/PreparedPutObject.java    | 150 -------
 .../storio/sqlite/operation/put/PutResolver.java   |  24 -
 .../storio/sqlite/operation/put/PutResult.java     | 182 --------
 .../storio/sqlite/operation/put/PutResults.java    | 127 ------
 .../operations/delete/DefaultDeleteResolver.java   |  33 ++
 .../sqlite/operations/delete/DeleteResolver.java   |  23 +
 .../sqlite/operations/delete/DeleteResult.java     |  98 ++++
 .../sqlite/operations/delete/DeleteResults.java    |  90 ++++
 .../sqlite/operations/delete/PreparedDelete.java   |  72 +++
 .../operations/delete/PreparedDeleteByQuery.java   | 131 ++++++
 .../delete/PreparedDeleteCollectionOfObjects.java  | 244 ++++++++++
 .../operations/delete/PreparedDeleteObject.java    | 150 +++++++
 .../operations/execute/PreparedExecuteSQL.java     | 146 ++++++
 .../sqlite/operations/get/DefaultGetResolver.java  |  36 ++
 .../storio/sqlite/operations/get/GetResolver.java  |  48 ++
 .../storio/sqlite/operations/get/PreparedGet.java  |  74 +++
 .../sqlite/operations/get/PreparedGetCursor.java   | 224 +++++++++
 .../operations/get/PreparedGetListOfObjects.java   | 292 ++++++++++++
 .../sqlite/operations/put/DefaultPutResolver.java  |  95 ++++
 .../storio/sqlite/operations/put/PreparedPut.java  |  94 ++++
 .../put/PreparedPutCollectionOfObjects.java        | 236 ++++++++++
 .../operations/put/PreparedPutContentValues.java   | 146 ++++++
 .../put/PreparedPutContentValuesIterable.java      | 211 +++++++++
 .../sqlite/operations/put/PreparedPutObject.java   | 150 +++++++
 .../storio/sqlite/operations/put/PutResolver.java  |  24 +
 .../storio/sqlite/operations/put/PutResult.java    | 182 ++++++++
 .../storio/sqlite/operations/put/PutResults.java   | 127 ++++++
 .../storio/sqlite/queries/DeleteQuery.java         | 211 +++++++++
 .../storio/sqlite/queries/InsertQuery.java         | 169 +++++++
 .../pushtorefresh/storio/sqlite/queries/Query.java | 500 +++++++++++++++++++++
 .../storio/sqlite/queries/RawQuery.java            | 249 ++++++++++
 .../storio/sqlite/queries/UpdateQuery.java         | 207 +++++++++
 .../storio/sqlite/query/DeleteQuery.java           | 211 ---------
 .../storio/sqlite/query/InsertQuery.java           | 169 -------
 .../pushtorefresh/storio/sqlite/query/Query.java   | 500 ---------------------
 .../storio/sqlite/query/RawQuery.java              | 249 ----------
 .../storio/sqlite/query/UpdateQuery.java           | 207 ---------
 .../storio/sqlite/SQLiteTypeMappingTest.java       |   6 +-
 .../sqlite/design/DeleteOperationDesignTest.java   |   6 +-
 .../sqlite/design/DesignTestStorIOSQLite.java      |  18 +-
 .../design/ExecuteSQLOperationDesignTest.java      |   2 +-
 .../sqlite/design/GetOperationDesignTest.java      |   4 +-
 .../sqlite/design/PutOperationDesignTest.java      |  12 +-
 .../storio/sqlite/design/UserTableMeta.java        |  18 +-
 .../sqlite/impl/DefaultStorIOSQLiteTest.java       |   6 +-
 .../delete/DefaultDeleteResolverTest.java          |  59 ---
 .../sqlite/operation/delete/DeleteResultTest.java  |  47 --
 .../sqlite/operation/delete/DeleteResultsTest.java |  40 --
 .../storio/sqlite/operation/delete/DeleteStub.java | 176 --------
 .../PreparedDeleteCollectionOfObjectsTest.java     | 285 ------------
 .../operation/delete/PreparedDeleteObjectTest.java | 143 ------
 .../storio/sqlite/operation/delete/TestItem.java   |  17 -
 .../operation/execute/PreparedExecuteSQLTest.java  | 153 -------
 .../operation/get/DefaultGetResolverTest.java      |  96 ----
 .../storio/sqlite/operation/get/GetCursorStub.java | 132 ------
 .../sqlite/operation/get/GetObjectsStub.java       | 226 ----------
 .../operation/get/PreparedGetCursorTest.java       |  74 ---
 .../get/PreparedGetListOfObjectsTest.java          | 276 ------------
 .../storio/sqlite/operation/get/TestItem.java      |  29 --
 .../operation/put/DefaultPutResolverTest.java      | 267 -----------
 .../put/PreparedPutCollectionOfObjectsTest.java    | 292 ------------
 .../put/PreparedPutContentValuesIterableTest.java  |  70 ---
 .../put/PreparedPutContentValuesTest.java          |  36 --
 .../operation/put/PreparedPutObjectTest.java       |  44 --
 .../sqlite/operation/put/PutContentValuesStub.java | 141 ------
 .../sqlite/operation/put/PutObjectsStub.java       | 216 ---------
 .../storio/sqlite/operation/put/TestItem.java      |  16 -
 .../delete/DefaultDeleteResolverTest.java          |  59 +++
 .../sqlite/operations/delete/DeleteResultTest.java |  47 ++
 .../operations/delete/DeleteResultsTest.java       |  40 ++
 .../sqlite/operations/delete/DeleteStub.java       | 176 ++++++++
 .../PreparedDeleteCollectionOfObjectsTest.java     | 285 ++++++++++++
 .../delete/PreparedDeleteObjectTest.java           | 143 ++++++
 .../storio/sqlite/operations/delete/TestItem.java  |  17 +
 .../operations/execute/PreparedExecuteSQLTest.java | 153 +++++++
 .../operations/get/DefaultGetResolverTest.java     |  96 ++++
 .../sqlite/operations/get/GetCursorStub.java       | 132 ++++++
 .../sqlite/operations/get/GetObjectsStub.java      | 226 ++++++++++
 .../operations/get/PreparedGetCursorTest.java      |  74 +++
 .../get/PreparedGetListOfObjectsTest.java          | 276 ++++++++++++
 .../storio/sqlite/operations/get/TestItem.java     |  29 ++
 .../operations/put/DefaultPutResolverTest.java     | 267 +++++++++++
 .../put/PreparedPutCollectionOfObjectsTest.java    | 292 ++++++++++++
 .../put/PreparedPutContentValuesIterableTest.java  |  70 +++
 .../put/PreparedPutContentValuesTest.java          |  36 ++
 .../operations/put/PreparedPutObjectTest.java      |  44 ++
 .../operations/put/PutContentValuesStub.java       | 141 ++++++
 .../sqlite/operations/put/PutObjectsStub.java      | 216 +++++++++
 .../storio/sqlite/operations/put/TestItem.java     |  16 +
 .../storio/sqlite/queries/DeleteQueryTest.java     |  72 +++
 .../storio/sqlite/queries/InsertQueryTest.java     |  47 ++
 .../storio/sqlite/queries/QueryTest.java           | 150 +++++++
 .../storio/sqlite/queries/RawQueryTest.java        |  78 ++++
 .../storio/sqlite/queries/UpdateQueryTest.java     |  63 +++
 .../storio/sqlite/query/DeleteQueryTest.java       |  72 ---
 .../storio/sqlite/query/InsertQueryTest.java       |  47 --
 .../storio/sqlite/query/QueryTest.java             | 150 -------
 .../storio/sqlite/query/RawQueryTest.java          |  78 ----
 .../storio/sqlite/query/UpdateQueryTest.java       |  63 ---
 .../DefaultStorIOContentResolverTest.java          |  10 +-
 .../sqlite/DefaultStorIOSQLiteTest.java            |   6 +-
 323 files changed, 15519 insertions(+), 15516 deletions(-)
 delete mode 100644 storio-common/src/main/java/com/pushtorefresh/storio/operation/PreparedOperation.java
 delete mode 100644 storio-common/src/main/java/com/pushtorefresh/storio/operation/group/GroupOperationResults.java
 delete mode 100644 storio-common/src/main/java/com/pushtorefresh/storio/operation/group/PreparedGroupOperation.java
 delete mode 100644 storio-common/src/main/java/com/pushtorefresh/storio/operation/internal/MapSomethingToExecuteAsBlocking.java
 delete mode 100644 storio-common/src/main/java/com/pushtorefresh/storio/operation/internal/OnSubscribeExecuteAsBlocking.java
 create mode 100644 storio-common/src/main/java/com/pushtorefresh/storio/operations/PreparedOperation.java
 create mode 100644 storio-common/src/main/java/com/pushtorefresh/storio/operations/group/GroupOperationResults.java
 create mode 100644 storio-common/src/main/java/com/pushtorefresh/storio/operations/group/PreparedGroupOperation.java
 create mode 100644 storio-common/src/main/java/com/pushtorefresh/storio/operations/internal/MapSomethingToExecuteAsBlocking.java
 create mode 100644 storio-common/src/main/java/com/pushtorefresh/storio/operations/internal/OnSubscribeExecuteAsBlocking.java
 delete mode 100644 storio-common/src/test/java/com/pushtorefresh/storio/operation/group/GroupOperationResultsTest.java
 delete mode 100644 storio-common/src/test/java/com/pushtorefresh/storio/operation/group/GroupOperationStub.java
 delete mode 100644 storio-common/src/test/java/com/pushtorefresh/storio/operation/internal/MapSomethingToExecuteAsBlockingTest.java
 delete mode 100644 storio-common/src/test/java/com/pushtorefresh/storio/operation/internal/OnSubscribeExecuteAsBlockingTest.java
 create mode 100644 storio-common/src/test/java/com/pushtorefresh/storio/operations/group/GroupOperationResultsTest.java
 create mode 100644 storio-common/src/test/java/com/pushtorefresh/storio/operations/group/GroupOperationStub.java
 create mode 100644 storio-common/src/test/java/com/pushtorefresh/storio/operations/internal/MapSomethingToExecuteAsBlockingTest.java
 create mode 100644 storio-common/src/test/java/com/pushtorefresh/storio/operations/internal/OnSubscribeExecuteAsBlockingTest.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DefaultDeleteResolver.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResolver.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResult.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResults.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDelete.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteByQuery.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteCollectionOfObjects.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteObject.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/DefaultGetResolver.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/GetResolver.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGet.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetCursor.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetListOfObjects.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/DefaultPutResolver.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPut.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutCollectionOfObjects.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValues.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValuesIterable.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutObject.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PutResolver.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PutResult.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PutResults.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DefaultDeleteResolver.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResolver.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResult.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResults.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDelete.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteByQuery.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteCollectionOfObjects.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteObject.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/DefaultGetResolver.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/GetResolver.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGet.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetCursor.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetListOfObjects.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/DefaultPutResolver.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPut.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutCollectionOfObjects.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValues.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValuesIterable.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutObject.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PutResolver.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PutResult.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PutResults.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/DeleteQuery.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/InsertQuery.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/Query.java
 create mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/UpdateQuery.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/DeleteQuery.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/InsertQuery.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/Query.java
 delete mode 100644 storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/UpdateQuery.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DefaultDeleteResolverTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteByQueryStub.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteObjectsStub.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResultTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResultsTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteByQueryTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteCollectionOfObjectsTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteObjectTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/TestItem.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/DefaultGetResolverTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/GetCursorStub.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/GetObjectsStub.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetCursorTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetListOfObjectsTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/TestItem.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/DefaultPutResolverTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutCollectionOfObjectsTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValuesIterableTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValuesTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutObjectTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PutContentValuesStub.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PutObjectsStub.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/TestItem.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DefaultDeleteResolverTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteByQueryStub.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteObjectsStub.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResultTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResultsTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteByQueryTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteCollectionOfObjectsTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteObjectTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/TestItem.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/DefaultGetResolverTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/GetCursorStub.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/GetObjectsStub.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetCursorTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetListOfObjectsTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/TestItem.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/DefaultPutResolverTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutCollectionOfObjectsTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValuesIterableTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValuesTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutObjectTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PutContentValuesStub.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PutObjectsStub.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/TestItem.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/DeleteQueryTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/InsertQueryTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/QueryTest.java
 create mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/UpdateQueryTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/DeleteQueryTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/InsertQueryTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/QueryTest.java
 delete mode 100644 storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/UpdateQueryTest.java
 delete mode 100644 storio-sqlite-annotation-processor/build.gradle
 delete mode 100644 storio-sqlite-annotation-processor/gradle.properties
 delete mode 100644 storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/ProcessingException.java
 delete mode 100644 storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/StorIOSQLiteProcessor.java
 delete mode 100644 storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/Common.java
 delete mode 100644 storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/DeleteResolverGenerator.java
 delete mode 100644 storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/GetResolverGenerator.java
 delete mode 100644 storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/PutResolverGenerator.java
 delete mode 100644 storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/QueryGenerator.java
 delete mode 100644 storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/introspection/JavaType.java
 delete mode 100644 storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/introspection/StorIOSQLiteColumnMeta.java
 delete mode 100644 storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/introspection/StorIOSQLiteTypeMeta.java
 delete mode 100644 storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/DeleteResolverGeneratorTest.java
 delete mode 100644 storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/GetResolverGeneratorTest.java
 delete mode 100644 storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/PutResolverGeneratorTest.java
 delete mode 100644 storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/QueryGeneratorTest.java
 delete mode 100644 storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/introspection/JavaTypeTest.java
 delete mode 100644 storio-sqlite-annotation/build.gradle
 delete mode 100644 storio-sqlite-annotation/gradle.properties
 delete mode 100644 storio-sqlite-annotation/src/main/java/com/pushtorefresh/storio/sqlite/annotation/StorIOSQLiteColumn.java
 delete mode 100644 storio-sqlite-annotation/src/main/java/com/pushtorefresh/storio/sqlite/annotation/StorIOSQLiteType.java
 create mode 100644 storio-sqlite-annotations-processor/build.gradle
 create mode 100644 storio-sqlite-annotations-processor/gradle.properties
 create mode 100644 storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/ProcessingException.java
 create mode 100644 storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/StorIOSQLiteProcessor.java
 create mode 100644 storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/Common.java
 create mode 100644 storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/DeleteResolverGenerator.java
 create mode 100644 storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/GetResolverGenerator.java
 create mode 100644 storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/PutResolverGenerator.java
 create mode 100644 storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/QueryGenerator.java
 create mode 100644 storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/JavaType.java
 create mode 100644 storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/StorIOSQLiteColumnMeta.java
 create mode 100644 storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/StorIOSQLiteTypeMeta.java
 create mode 100644 storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/DeleteResolverGeneratorTest.java
 create mode 100644 storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/GetResolverGeneratorTest.java
 create mode 100644 storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/PutResolverGeneratorTest.java
 create mode 100644 storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/QueryGeneratorTest.java
 create mode 100644 storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/JavaTypeTest.java
 create mode 100644 storio-sqlite-annotations/build.gradle
 create mode 100644 storio-sqlite-annotations/gradle.properties
 create mode 100644 storio-sqlite-annotations/src/main/java/com/pushtorefresh/storio/sqlite/annotations/StorIOSQLiteColumn.java
 create mode 100644 storio-sqlite-annotations/src/main/java/com/pushtorefresh/storio/sqlite/annotations/StorIOSQLiteType.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DefaultDeleteResolver.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResolver.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResult.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResults.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDelete.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteByQuery.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteCollectionOfObjects.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteObject.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/execute/PreparedExecuteSQL.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/DefaultGetResolver.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/GetResolver.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGet.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetCursor.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetListOfObjects.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/DefaultPutResolver.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPut.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutCollectionOfObjects.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValues.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValuesIterable.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutObject.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PutResolver.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PutResult.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PutResults.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DefaultDeleteResolver.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResolver.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResult.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResults.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDelete.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteByQuery.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteCollectionOfObjects.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteObject.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/execute/PreparedExecuteSQL.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/DefaultGetResolver.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/GetResolver.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGet.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetCursor.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetListOfObjects.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/DefaultPutResolver.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPut.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutCollectionOfObjects.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValues.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValuesIterable.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutObject.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PutResolver.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PutResult.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PutResults.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/DeleteQuery.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/InsertQuery.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/Query.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/RawQuery.java
 create mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/UpdateQuery.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/DeleteQuery.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/InsertQuery.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/Query.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/RawQuery.java
 delete mode 100644 storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/UpdateQuery.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DefaultDeleteResolverTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResultTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResultsTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteStub.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteCollectionOfObjectsTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteObjectTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/TestItem.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/execute/PreparedExecuteSQLTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/DefaultGetResolverTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/GetCursorStub.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/GetObjectsStub.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetCursorTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetListOfObjectsTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/TestItem.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/DefaultPutResolverTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutCollectionOfObjectsTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValuesIterableTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValuesTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutObjectTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PutContentValuesStub.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PutObjectsStub.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/TestItem.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DefaultDeleteResolverTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResultTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResultsTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteStub.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteCollectionOfObjectsTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteObjectTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/TestItem.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/execute/PreparedExecuteSQLTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/DefaultGetResolverTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/GetCursorStub.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/GetObjectsStub.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetCursorTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetListOfObjectsTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/TestItem.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/DefaultPutResolverTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutCollectionOfObjectsTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValuesIterableTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValuesTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutObjectTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PutContentValuesStub.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PutObjectsStub.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/TestItem.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/DeleteQueryTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/InsertQueryTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/QueryTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/RawQueryTest.java
 create mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/UpdateQueryTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/DeleteQueryTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/InsertQueryTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/QueryTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/RawQueryTest.java
 delete mode 100644 storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/UpdateQueryTest.java

diff --git a/build.gradle b/build.gradle
index 5b4c6ba..e4c4d34 100644
--- a/build.gradle
+++ b/build.gradle
@@ -45,8 +45,8 @@ ext.libraries = [
         storIOCommon                   : project(':storio-common'),
         storIOSQLite                   : project(':storio-sqlite'),
         storIOContentResolver          : project(':storio-content-resolver'),
-        storIOSQLiteAnnotation         : project(':storio-sqlite-annotation'),
-        storIOSQLiteAnnotationProcessor: project('storio-sqlite-annotation-processor'),
+        storIOSQLiteAnnotation         : project(':storio-sqlite-annotations'),
+        storIOSQLiteAnnotationProcessor: project(':storio-sqlite-annotations-processor'),
         storIOTestCommon               : project(':storio-test-common'),
         
         // Libraries for tests and sample app
diff --git a/settings.gradle b/settings.gradle
index 4e0cf13..29cb7ef 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -2,7 +2,10 @@ include ':storio-common'
 include ':storio-test-common'
 include ':storio-sqlite'
 include ':storio-content-resolver'
-include ':storio-sample-app'
+
+include ':storio-sqlite-annotations'
+include ':storio-sqlite-annotations-processor'
+
 include ':storio-test-without-rxjava'
-include ':storio-sqlite-annotation'
-include ':storio-sqlite-annotation-processor'
\ No newline at end of file
+
+include ':storio-sample-app'
diff --git a/storio-common/src/main/java/com/pushtorefresh/storio/operation/PreparedOperation.java b/storio-common/src/main/java/com/pushtorefresh/storio/operation/PreparedOperation.java
deleted file mode 100644
index cb87279..0000000
--- a/storio-common/src/main/java/com/pushtorefresh/storio/operation/PreparedOperation.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.pushtorefresh.storio.operation;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.WorkerThread;
-
-import rx.Observable;
-
-/**
- * Common API of all prepared operations
- *
- * @param <Result> type of result
- */
-public interface PreparedOperation<Result> {
-
-    /**
-     * Executes operation synchronously in current thread.
-     * <p/>
-     * Notice: Blocking I/O operation should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, execute blocking I/O operation only from background thread.
-     * See {@link WorkerThread}.
-     *
-     * @return non-null result of operation.
-     */
-    @NonNull
-    @WorkerThread
-    Result executeAsBlocking();
-
-    /**
-     * Creates {@link rx.Observable} that emits result of Operation.
-     * <p/>
-     * Observable may be "Hot" or "Cold", please read documentation of the concrete implementation.
-     *
-     * @return observable result of operation with only one {@link rx.Observer#onNext(Object)} call.
-     */
-    @NonNull
-    Observable<Result> createObservable();
-}
diff --git a/storio-common/src/main/java/com/pushtorefresh/storio/operation/group/GroupOperationResults.java b/storio-common/src/main/java/com/pushtorefresh/storio/operation/group/GroupOperationResults.java
deleted file mode 100644
index 10acb40..0000000
--- a/storio-common/src/main/java/com/pushtorefresh/storio/operation/group/GroupOperationResults.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.pushtorefresh.storio.operation.group;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.operation.PreparedOperation;
-
-import java.util.Collections;
-import java.util.Map;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-
-/**
- * Immutable container for results of {@link PreparedGroupOperation}
- * Thread-safe
- * <p/>
- * Unfortunately, we can not generify it because each Operation can return different type of result
- */
-public final class GroupOperationResults {
-
-    @NonNull
-    private final Map<PreparedOperation<?>, Object> results;
-
-    /**
-     * Creates new {@link GroupOperationResults}
-     *
-     * @param results non-null map of pairs (operation, resultOfOperation)
-     */
-    private GroupOperationResults(@NonNull Map<PreparedOperation<?>, Object> results) {
-        this.results = Collections.unmodifiableMap(results);
-    }
-
-    /**
-     * Creates new instance of {@link GroupOperationResults}
-     *
-     * @param results non-null map of pairs (operation, resultOfOperation)
-     * @return immutable container for results of {@link PreparedGroupOperation}
-     */
-    @NonNull
-    static GroupOperationResults newInstance(@NonNull Map<PreparedOperation<?>, Object> results) {
-        checkNotNull(results, "Please specify results of Group Operation");
-        return new GroupOperationResults(results);
-    }
-
-    /**
-     * Gets immutable map of pairs (operation, resultOfOperation)
-     *
-     * @return non-null map of pairs (operation, resultOfOperation)
-     */
-    @NonNull
-    public Map<PreparedOperation<?>, Object> results() {
-        return results;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        GroupOperationResults that = (GroupOperationResults) o;
-
-        return results.equals(that.results);
-    }
-
-    @Override
-    public int hashCode() {
-        return results.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        return "GroupOperationResults{" +
-                "results=" + results +
-                '}';
-    }
-}
diff --git a/storio-common/src/main/java/com/pushtorefresh/storio/operation/group/PreparedGroupOperation.java b/storio-common/src/main/java/com/pushtorefresh/storio/operation/group/PreparedGroupOperation.java
deleted file mode 100644
index 6251bbb..0000000
--- a/storio-common/src/main/java/com/pushtorefresh/storio/operation/group/PreparedGroupOperation.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.pushtorefresh.storio.operation.group;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.operation.PreparedOperation;
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Group Operation for StorIO implementations.
- * <p/>
- * Allows group execution of any combination of {@link PreparedOperation}.
- * <p/>
- * And yes, you can execute {@link PreparedGroupOperation}
- * as part of {@link PreparedGroupOperation}
- * since it implements {@link PreparedOperation} :).
- */
-public class PreparedGroupOperation implements PreparedOperation<GroupOperationResults> {
-
-    @NonNull
-    private final List<PreparedOperation<?>> preparedOperations;
-
-    protected PreparedGroupOperation(@NonNull List<PreparedOperation<?>> preparedOperations) {
-        this.preparedOperations = preparedOperations;
-    }
-
-    /**
-     * Executes Group Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null result of Group Operation.
-     */
-    @WorkerThread
-    @NonNull
-    @Override
-    public GroupOperationResults executeAsBlocking() {
-        final Map<PreparedOperation<?>, Object> results = new HashMap<PreparedOperation<?>, Object>();
-
-        for (PreparedOperation<?> preparedOperation : preparedOperations) {
-            final Object result = preparedOperation.executeAsBlocking();
-            results.put(preparedOperation, result);
-        }
-
-        return GroupOperationResults.newInstance(results);
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Group Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * Group Operation only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Group Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<GroupOperationResults> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-}
diff --git a/storio-common/src/main/java/com/pushtorefresh/storio/operation/internal/MapSomethingToExecuteAsBlocking.java b/storio-common/src/main/java/com/pushtorefresh/storio/operation/internal/MapSomethingToExecuteAsBlocking.java
deleted file mode 100644
index 2278c8e..0000000
--- a/storio-common/src/main/java/com/pushtorefresh/storio/operation/internal/MapSomethingToExecuteAsBlocking.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.pushtorefresh.storio.operation.internal;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.operation.PreparedOperation;
-
-import rx.functions.Func1;
-
-/**
- * Required to avoid problems with ClassLoader when RxJava is not in ClassPath
- * We can not use anonymous classes from RxJava directly in StorIO, ClassLoader won't be happy :(
- * <p/>
- * For internal usage only!
- */
-public final class MapSomethingToExecuteAsBlocking<Something, Result> implements Func1<Something, Result> {
-
-    @NonNull
-    private final PreparedOperation<Result> preparedOperation;
-
-    private MapSomethingToExecuteAsBlocking(@NonNull PreparedOperation<Result> preparedOperation) {
-        this.preparedOperation = preparedOperation;
-    }
-
-    /**
-     * Creates new instance of {@link MapSomethingToExecuteAsBlocking}
-     *
-     * @param preparedOperation non-null instance of {@link PreparedOperation} which will be used to react on calls to rx function
-     * @param <Something>       type of map argument
-     * @param <Result>          type of result of rx map function
-     * @return new instance of {@link MapSomethingToExecuteAsBlocking}
-     */
-    @NonNull
-    public static <Something, Result> Func1<Something, Result> newInstance(@NonNull PreparedOperation<Result> preparedOperation) {
-        return new MapSomethingToExecuteAsBlocking<Something, Result>(preparedOperation);
-    }
-
-    @Override
-    public Result call(Something changes) {
-        return preparedOperation.executeAsBlocking();
-    }
-}
diff --git a/storio-common/src/main/java/com/pushtorefresh/storio/operation/internal/OnSubscribeExecuteAsBlocking.java b/storio-common/src/main/java/com/pushtorefresh/storio/operation/internal/OnSubscribeExecuteAsBlocking.java
deleted file mode 100644
index 77c3798..0000000
--- a/storio-common/src/main/java/com/pushtorefresh/storio/operation/internal/OnSubscribeExecuteAsBlocking.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.pushtorefresh.storio.operation.internal;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.operation.PreparedOperation;
-
-import rx.Observable;
-import rx.Subscriber;
-
-/**
- * Required to avoid problems with ClassLoader when RxJava is not in ClassPath
- * We can not use anonymous classes from RxJava directly in StorIO, ClassLoader won't be happy :(
- * <p/>
- * For internal usage only!
- */
-public final class OnSubscribeExecuteAsBlocking<Result> implements Observable.OnSubscribe<Result> {
-
-    @NonNull
-    private final PreparedOperation<Result> preparedOperation;
-
-    private OnSubscribeExecuteAsBlocking(@NonNull PreparedOperation<Result> preparedOperation) {
-        this.preparedOperation = preparedOperation;
-    }
-
-    /**
-     * Creates new instance of {@link OnSubscribeExecuteAsBlocking}
-     *
-     * @param preparedOperation non-null instance of {@link PreparedOperation} which will be used to provide result to subscribers
-     * @param <Result>          type of result of {@link PreparedOperation}
-     * @return new instance of {@link OnSubscribeExecuteAsBlocking}
-     */
-    @NonNull
-    public static <Result> Observable.OnSubscribe<Result> newInstance(@NonNull PreparedOperation<Result> preparedOperation) {
-        return new OnSubscribeExecuteAsBlocking<Result>(preparedOperation);
-    }
-
-    @Override
-    public void call(Subscriber<? super Result> subscriber) {
-        final Result result = preparedOperation.executeAsBlocking();
-
-        if (!subscriber.isUnsubscribed()) {
-            subscriber.onNext(result);
-            subscriber.onCompleted();
-        }
-    }
-}
diff --git a/storio-common/src/main/java/com/pushtorefresh/storio/operations/PreparedOperation.java b/storio-common/src/main/java/com/pushtorefresh/storio/operations/PreparedOperation.java
new file mode 100644
index 0000000..33a8ed3
--- /dev/null
+++ b/storio-common/src/main/java/com/pushtorefresh/storio/operations/PreparedOperation.java
@@ -0,0 +1,38 @@
+package com.pushtorefresh.storio.operations;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.WorkerThread;
+
+import rx.Observable;
+
+/**
+ * Common API of all prepared operations
+ *
+ * @param <Result> type of result
+ */
+public interface PreparedOperation<Result> {
+
+    /**
+     * Executes operation synchronously in current thread.
+     * <p/>
+     * Notice: Blocking I/O operation should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, execute blocking I/O operation only from background thread.
+     * See {@link WorkerThread}.
+     *
+     * @return non-null result of operation.
+     */
+    @NonNull
+    @WorkerThread
+    Result executeAsBlocking();
+
+    /**
+     * Creates {@link rx.Observable} that emits result of Operation.
+     * <p/>
+     * Observable may be "Hot" or "Cold", please read documentation of the concrete implementation.
+     *
+     * @return observable result of operation with only one {@link rx.Observer#onNext(Object)} call.
+     */
+    @NonNull
+    Observable<Result> createObservable();
+}
diff --git a/storio-common/src/main/java/com/pushtorefresh/storio/operations/group/GroupOperationResults.java b/storio-common/src/main/java/com/pushtorefresh/storio/operations/group/GroupOperationResults.java
new file mode 100644
index 0000000..48a73ae
--- /dev/null
+++ b/storio-common/src/main/java/com/pushtorefresh/storio/operations/group/GroupOperationResults.java
@@ -0,0 +1,75 @@
+package com.pushtorefresh.storio.operations.group;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.operations.PreparedOperation;
+
+import java.util.Collections;
+import java.util.Map;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+
+/**
+ * Immutable container for results of {@link PreparedGroupOperation}
+ * Thread-safe
+ * <p/>
+ * Unfortunately, we can not generify it because each Operation can return different type of result
+ */
+public final class GroupOperationResults {
+
+    @NonNull
+    private final Map<PreparedOperation<?>, Object> results;
+
+    /**
+     * Creates new {@link GroupOperationResults}
+     *
+     * @param results non-null map of pairs (operation, resultOfOperation)
+     */
+    private GroupOperationResults(@NonNull Map<PreparedOperation<?>, Object> results) {
+        this.results = Collections.unmodifiableMap(results);
+    }
+
+    /**
+     * Creates new instance of {@link GroupOperationResults}
+     *
+     * @param results non-null map of pairs (operation, resultOfOperation)
+     * @return immutable container for results of {@link PreparedGroupOperation}
+     */
+    @NonNull
+    static GroupOperationResults newInstance(@NonNull Map<PreparedOperation<?>, Object> results) {
+        checkNotNull(results, "Please specify results of Group Operation");
+        return new GroupOperationResults(results);
+    }
+
+    /**
+     * Gets immutable map of pairs (operation, resultOfOperation)
+     *
+     * @return non-null map of pairs (operation, resultOfOperation)
+     */
+    @NonNull
+    public Map<PreparedOperation<?>, Object> results() {
+        return results;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        GroupOperationResults that = (GroupOperationResults) o;
+
+        return results.equals(that.results);
+    }
+
+    @Override
+    public int hashCode() {
+        return results.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "GroupOperationResults{" +
+                "results=" + results +
+                '}';
+    }
+}
diff --git a/storio-common/src/main/java/com/pushtorefresh/storio/operations/group/PreparedGroupOperation.java b/storio-common/src/main/java/com/pushtorefresh/storio/operations/group/PreparedGroupOperation.java
new file mode 100644
index 0000000..c925992
--- /dev/null
+++ b/storio-common/src/main/java/com/pushtorefresh/storio/operations/group/PreparedGroupOperation.java
@@ -0,0 +1,82 @@
+package com.pushtorefresh.storio.operations.group;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.operations.PreparedOperation;
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Group Operation for StorIO implementations.
+ * <p/>
+ * Allows group execution of any combination of {@link PreparedOperation}.
+ * <p/>
+ * And yes, you can execute {@link PreparedGroupOperation}
+ * as part of {@link PreparedGroupOperation}
+ * since it implements {@link PreparedOperation} :).
+ */
+public class PreparedGroupOperation implements PreparedOperation<GroupOperationResults> {
+
+    @NonNull
+    private final List<PreparedOperation<?>> preparedOperations;
+
+    protected PreparedGroupOperation(@NonNull List<PreparedOperation<?>> preparedOperations) {
+        this.preparedOperations = preparedOperations;
+    }
+
+    /**
+     * Executes Group Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null result of Group Operation.
+     */
+    @WorkerThread
+    @NonNull
+    @Override
+    public GroupOperationResults executeAsBlocking() {
+        final Map<PreparedOperation<?>, Object> results = new HashMap<PreparedOperation<?>, Object>();
+
+        for (PreparedOperation<?> preparedOperation : preparedOperations) {
+            final Object result = preparedOperation.executeAsBlocking();
+            results.put(preparedOperation, result);
+        }
+
+        return GroupOperationResults.newInstance(results);
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Group Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * Group Operation only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Group Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<GroupOperationResults> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+}
diff --git a/storio-common/src/main/java/com/pushtorefresh/storio/operations/internal/MapSomethingToExecuteAsBlocking.java b/storio-common/src/main/java/com/pushtorefresh/storio/operations/internal/MapSomethingToExecuteAsBlocking.java
new file mode 100644
index 0000000..99490b0
--- /dev/null
+++ b/storio-common/src/main/java/com/pushtorefresh/storio/operations/internal/MapSomethingToExecuteAsBlocking.java
@@ -0,0 +1,41 @@
+package com.pushtorefresh.storio.operations.internal;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.operations.PreparedOperation;
+
+import rx.functions.Func1;
+
+/**
+ * Required to avoid problems with ClassLoader when RxJava is not in ClassPath
+ * We can not use anonymous classes from RxJava directly in StorIO, ClassLoader won't be happy :(
+ * <p/>
+ * For internal usage only!
+ */
+public final class MapSomethingToExecuteAsBlocking<Something, Result> implements Func1<Something, Result> {
+
+    @NonNull
+    private final PreparedOperation<Result> preparedOperation;
+
+    private MapSomethingToExecuteAsBlocking(@NonNull PreparedOperation<Result> preparedOperation) {
+        this.preparedOperation = preparedOperation;
+    }
+
+    /**
+     * Creates new instance of {@link MapSomethingToExecuteAsBlocking}
+     *
+     * @param preparedOperation non-null instance of {@link PreparedOperation} which will be used to react on calls to rx function
+     * @param <Something>       type of map argument
+     * @param <Result>          type of result of rx map function
+     * @return new instance of {@link MapSomethingToExecuteAsBlocking}
+     */
+    @NonNull
+    public static <Something, Result> Func1<Something, Result> newInstance(@NonNull PreparedOperation<Result> preparedOperation) {
+        return new MapSomethingToExecuteAsBlocking<Something, Result>(preparedOperation);
+    }
+
+    @Override
+    public Result call(Something changes) {
+        return preparedOperation.executeAsBlocking();
+    }
+}
diff --git a/storio-common/src/main/java/com/pushtorefresh/storio/operations/internal/OnSubscribeExecuteAsBlocking.java b/storio-common/src/main/java/com/pushtorefresh/storio/operations/internal/OnSubscribeExecuteAsBlocking.java
new file mode 100644
index 0000000..54251bf
--- /dev/null
+++ b/storio-common/src/main/java/com/pushtorefresh/storio/operations/internal/OnSubscribeExecuteAsBlocking.java
@@ -0,0 +1,46 @@
+package com.pushtorefresh.storio.operations.internal;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.operations.PreparedOperation;
+
+import rx.Observable;
+import rx.Subscriber;
+
+/**
+ * Required to avoid problems with ClassLoader when RxJava is not in ClassPath
+ * We can not use anonymous classes from RxJava directly in StorIO, ClassLoader won't be happy :(
+ * <p/>
+ * For internal usage only!
+ */
+public final class OnSubscribeExecuteAsBlocking<Result> implements Observable.OnSubscribe<Result> {
+
+    @NonNull
+    private final PreparedOperation<Result> preparedOperation;
+
+    private OnSubscribeExecuteAsBlocking(@NonNull PreparedOperation<Result> preparedOperation) {
+        this.preparedOperation = preparedOperation;
+    }
+
+    /**
+     * Creates new instance of {@link OnSubscribeExecuteAsBlocking}
+     *
+     * @param preparedOperation non-null instance of {@link PreparedOperation} which will be used to provide result to subscribers
+     * @param <Result>          type of result of {@link PreparedOperation}
+     * @return new instance of {@link OnSubscribeExecuteAsBlocking}
+     */
+    @NonNull
+    public static <Result> Observable.OnSubscribe<Result> newInstance(@NonNull PreparedOperation<Result> preparedOperation) {
+        return new OnSubscribeExecuteAsBlocking<Result>(preparedOperation);
+    }
+
+    @Override
+    public void call(Subscriber<? super Result> subscriber) {
+        final Result result = preparedOperation.executeAsBlocking();
+
+        if (!subscriber.isUnsubscribed()) {
+            subscriber.onNext(result);
+            subscriber.onCompleted();
+        }
+    }
+}
diff --git a/storio-common/src/test/java/com/pushtorefresh/storio/operation/group/GroupOperationResultsTest.java b/storio-common/src/test/java/com/pushtorefresh/storio/operation/group/GroupOperationResultsTest.java
deleted file mode 100644
index 4e2d208..0000000
--- a/storio-common/src/test/java/com/pushtorefresh/storio/operation/group/GroupOperationResultsTest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.pushtorefresh.storio.operation.group;
-
-import com.pushtorefresh.storio.operation.PreparedOperation;
-
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-
-public class GroupOperationResultsTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void nullResults() {
-        GroupOperationResults.newInstance(null);
-    }
-
-    @Test
-    public void results() {
-        final Map<PreparedOperation<?>, Object> results = new HashMap<PreparedOperation<?>, Object>();
-
-        results.put(mock(PreparedOperation.class), mock(Object.class));
-        results.put(mock(PreparedOperation.class), mock(Object.class));
-        results.put(mock(PreparedOperation.class), mock(Object.class));
-
-        final GroupOperationResults groupOperationResults = GroupOperationResults.newInstance(results);
-        assertEquals(results, groupOperationResults.results());
-    }
-}
diff --git a/storio-common/src/test/java/com/pushtorefresh/storio/operation/group/GroupOperationStub.java b/storio-common/src/test/java/com/pushtorefresh/storio/operation/group/GroupOperationStub.java
deleted file mode 100644
index df365e0..0000000
--- a/storio-common/src/test/java/com/pushtorefresh/storio/operation/group/GroupOperationStub.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.pushtorefresh.storio.operation.group;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.operation.PreparedOperation;
-import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import rx.Observable;
-import rx.functions.Action1;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-// we don't want to violate DRY in tests
-class GroupOperationStub {
-
-    final List<PreparedOperation<?>> preparedOperations;
-    final Map<PreparedOperation<?>, Object> results;
-
-    private GroupOperationStub() {
-        preparedOperations = new ArrayList<PreparedOperation<?>>();
-        results = new HashMap<PreparedOperation<?>, Object>();
-
-        for (int i = 0; i < 3; i++) {
-            final PreparedOperation<?> preparedOperation = mock(PreparedOperation.class);
-            final Object result = mock(Object.class);
-
-            when(preparedOperation.executeAsBlocking())
-                    .thenReturn(result);
-
-            preparedOperations.add(preparedOperation);
-            results.put(preparedOperation, result);
-        }
-    }
-
-    @NonNull
-    static GroupOperationStub newInstance() {
-        return new GroupOperationStub();
-    }
-
-    void verifyBehaviorOfExecuteAsBlocking(@NonNull GroupOperationResults groupOperationResults) {
-        assertEquals(results, groupOperationResults.results());
-
-        for (PreparedOperation<?> preparedOperation : preparedOperations) {
-            verify(preparedOperation, times(1)).executeAsBlocking();
-            verify(preparedOperation, times(0)).createObservable();
-
-            final Object expectedResultOfOperation = results.get(preparedOperation);
-            final Object actualResultOfOperation = groupOperationResults.results().get(preparedOperation);
-
-            assertEquals(expectedResultOfOperation, actualResultOfOperation);
-        }
-    }
-
-    void verifyBehaviorOfObservable(@NonNull Observable<GroupOperationResults> groupOperationResultsObservable) {
-        new ObservableBehaviorChecker<GroupOperationResults>()
-                .observable(groupOperationResultsObservable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<GroupOperationResults>() {
-                    @Override
-                    public void call(GroupOperationResults groupOperationResults) {
-                        verifyBehaviorOfExecuteAsBlocking(groupOperationResults);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-}
diff --git a/storio-common/src/test/java/com/pushtorefresh/storio/operation/internal/MapSomethingToExecuteAsBlockingTest.java b/storio-common/src/test/java/com/pushtorefresh/storio/operation/internal/MapSomethingToExecuteAsBlockingTest.java
deleted file mode 100644
index c60d243..0000000
--- a/storio-common/src/test/java/com/pushtorefresh/storio/operation/internal/MapSomethingToExecuteAsBlockingTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.pushtorefresh.storio.operation.internal;
-
-import com.pushtorefresh.storio.operation.PreparedOperation;
-
-import org.junit.Test;
-
-import rx.Observable;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class MapSomethingToExecuteAsBlockingTest {
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void verifyBehavior() {
-        final PreparedOperation<String> preparedOperation = mock(PreparedOperation.class);
-
-        final String expectedMapResult = "expected_string";
-
-        when(preparedOperation.executeAsBlocking())
-                .thenReturn(expectedMapResult);
-
-        final String actualMapResult = Observable.just(1)
-                .map(MapSomethingToExecuteAsBlocking.newInstance(preparedOperation))
-                .toBlocking()
-                .first();
-
-        verify(preparedOperation, times(1)).executeAsBlocking();
-        verify(preparedOperation, times(0)).createObservable();
-
-        assertEquals(expectedMapResult, actualMapResult);
-    }
-}
diff --git a/storio-common/src/test/java/com/pushtorefresh/storio/operation/internal/OnSubscribeExecuteAsBlockingTest.java b/storio-common/src/test/java/com/pushtorefresh/storio/operation/internal/OnSubscribeExecuteAsBlockingTest.java
deleted file mode 100644
index f75c0c4..0000000
--- a/storio-common/src/test/java/com/pushtorefresh/storio/operation/internal/OnSubscribeExecuteAsBlockingTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.pushtorefresh.storio.operation.internal;
-
-import com.pushtorefresh.storio.operation.PreparedOperation;
-
-import org.junit.Test;
-
-import rx.Observable;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class OnSubscribeExecuteAsBlockingTest {
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void verifyBehavior() {
-        final PreparedOperation<String> preparedOperation = mock(PreparedOperation.class);
-
-        final String expectedResult = "expected_string";
-
-        when(preparedOperation.executeAsBlocking())
-                .thenReturn(expectedResult);
-
-        final String actualResult = Observable.create(OnSubscribeExecuteAsBlocking.newInstance(preparedOperation))
-                .toBlocking()
-                .first();
-
-        verify(preparedOperation, times(1)).executeAsBlocking();
-        verify(preparedOperation, times(0)).createObservable();
-
-        assertEquals(expectedResult, actualResult);
-    }
-}
diff --git a/storio-common/src/test/java/com/pushtorefresh/storio/operations/group/GroupOperationResultsTest.java b/storio-common/src/test/java/com/pushtorefresh/storio/operations/group/GroupOperationResultsTest.java
new file mode 100644
index 0000000..6edea57
--- /dev/null
+++ b/storio-common/src/test/java/com/pushtorefresh/storio/operations/group/GroupOperationResultsTest.java
@@ -0,0 +1,32 @@
+package com.pushtorefresh.storio.operations.group;
+
+import com.pushtorefresh.storio.operations.PreparedOperation;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+public class GroupOperationResultsTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void nullResults() {
+        GroupOperationResults.newInstance(null);
+    }
+
+    @Test
+    public void results() {
+        final Map<PreparedOperation<?>, Object> results = new HashMap<PreparedOperation<?>, Object>();
+
+        results.put(mock(PreparedOperation.class), mock(Object.class));
+        results.put(mock(PreparedOperation.class), mock(Object.class));
+        results.put(mock(PreparedOperation.class), mock(Object.class));
+
+        final GroupOperationResults groupOperationResults = GroupOperationResults.newInstance(results);
+        assertEquals(results, groupOperationResults.results());
+    }
+}
diff --git a/storio-common/src/test/java/com/pushtorefresh/storio/operations/group/GroupOperationStub.java b/storio-common/src/test/java/com/pushtorefresh/storio/operations/group/GroupOperationStub.java
new file mode 100644
index 0000000..1183f5b
--- /dev/null
+++ b/storio-common/src/test/java/com/pushtorefresh/storio/operations/group/GroupOperationStub.java
@@ -0,0 +1,75 @@
+package com.pushtorefresh.storio.operations.group;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.operations.PreparedOperation;
+import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import rx.Observable;
+import rx.functions.Action1;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+// we don't want to violate DRY in tests
+class GroupOperationStub {
+
+    final List<PreparedOperation<?>> preparedOperations;
+    final Map<PreparedOperation<?>, Object> results;
+
+    private GroupOperationStub() {
+        preparedOperations = new ArrayList<PreparedOperation<?>>();
+        results = new HashMap<PreparedOperation<?>, Object>();
+
+        for (int i = 0; i < 3; i++) {
+            final PreparedOperation<?> preparedOperation = mock(PreparedOperation.class);
+            final Object result = mock(Object.class);
+
+            when(preparedOperation.executeAsBlocking())
+                    .thenReturn(result);
+
+            preparedOperations.add(preparedOperation);
+            results.put(preparedOperation, result);
+        }
+    }
+
+    @NonNull
+    static GroupOperationStub newInstance() {
+        return new GroupOperationStub();
+    }
+
+    void verifyBehaviorOfExecuteAsBlocking(@NonNull GroupOperationResults groupOperationResults) {
+        assertEquals(results, groupOperationResults.results());
+
+        for (PreparedOperation<?> preparedOperation : preparedOperations) {
+            verify(preparedOperation, times(1)).executeAsBlocking();
+            verify(preparedOperation, times(0)).createObservable();
+
+            final Object expectedResultOfOperation = results.get(preparedOperation);
+            final Object actualResultOfOperation = groupOperationResults.results().get(preparedOperation);
+
+            assertEquals(expectedResultOfOperation, actualResultOfOperation);
+        }
+    }
+
+    void verifyBehaviorOfObservable(@NonNull Observable<GroupOperationResults> groupOperationResultsObservable) {
+        new ObservableBehaviorChecker<GroupOperationResults>()
+                .observable(groupOperationResultsObservable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<GroupOperationResults>() {
+                    @Override
+                    public void call(GroupOperationResults groupOperationResults) {
+                        verifyBehaviorOfExecuteAsBlocking(groupOperationResults);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+}
diff --git a/storio-common/src/test/java/com/pushtorefresh/storio/operations/internal/MapSomethingToExecuteAsBlockingTest.java b/storio-common/src/test/java/com/pushtorefresh/storio/operations/internal/MapSomethingToExecuteAsBlockingTest.java
new file mode 100644
index 0000000..a90fa15
--- /dev/null
+++ b/storio-common/src/test/java/com/pushtorefresh/storio/operations/internal/MapSomethingToExecuteAsBlockingTest.java
@@ -0,0 +1,37 @@
+package com.pushtorefresh.storio.operations.internal;
+
+import com.pushtorefresh.storio.operations.PreparedOperation;
+
+import org.junit.Test;
+
+import rx.Observable;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class MapSomethingToExecuteAsBlockingTest {
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void verifyBehavior() {
+        final PreparedOperation<String> preparedOperation = mock(PreparedOperation.class);
+
+        final String expectedMapResult = "expected_string";
+
+        when(preparedOperation.executeAsBlocking())
+                .thenReturn(expectedMapResult);
+
+        final String actualMapResult = Observable.just(1)
+                .map(MapSomethingToExecuteAsBlocking.newInstance(preparedOperation))
+                .toBlocking()
+                .first();
+
+        verify(preparedOperation, times(1)).executeAsBlocking();
+        verify(preparedOperation, times(0)).createObservable();
+
+        assertEquals(expectedMapResult, actualMapResult);
+    }
+}
diff --git a/storio-common/src/test/java/com/pushtorefresh/storio/operations/internal/OnSubscribeExecuteAsBlockingTest.java b/storio-common/src/test/java/com/pushtorefresh/storio/operations/internal/OnSubscribeExecuteAsBlockingTest.java
new file mode 100644
index 0000000..a044576
--- /dev/null
+++ b/storio-common/src/test/java/com/pushtorefresh/storio/operations/internal/OnSubscribeExecuteAsBlockingTest.java
@@ -0,0 +1,36 @@
+package com.pushtorefresh.storio.operations.internal;
+
+import com.pushtorefresh.storio.operations.PreparedOperation;
+
+import org.junit.Test;
+
+import rx.Observable;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class OnSubscribeExecuteAsBlockingTest {
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void verifyBehavior() {
+        final PreparedOperation<String> preparedOperation = mock(PreparedOperation.class);
+
+        final String expectedResult = "expected_string";
+
+        when(preparedOperation.executeAsBlocking())
+                .thenReturn(expectedResult);
+
+        final String actualResult = Observable.create(OnSubscribeExecuteAsBlocking.newInstance(preparedOperation))
+                .toBlocking()
+                .first();
+
+        verify(preparedOperation, times(1)).executeAsBlocking();
+        verify(preparedOperation, times(0)).createObservable();
+
+        assertEquals(expectedResult, actualResult);
+    }
+}
diff --git a/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/BaseTest.java b/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/BaseTest.java
index 502f858..0484b08 100644
--- a/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/BaseTest.java
+++ b/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/BaseTest.java
@@ -7,11 +7,11 @@
 import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
 import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
 import com.pushtorefresh.storio.contentresolver.impl.DefaultStorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResult;
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResults;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResult;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResults;
-import com.pushtorefresh.storio.contentresolver.query.Query;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResult;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResults;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResult;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResults;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
 
 import org.junit.Before;
 
diff --git a/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/DeleteTest.java b/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/DeleteTest.java
index eb31107..7891446 100644
--- a/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/DeleteTest.java
+++ b/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/DeleteTest.java
@@ -2,7 +2,7 @@
 
 import android.support.test.runner.AndroidJUnit4;
 
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResults;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResults;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/InsertTest.java b/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/InsertTest.java
index 479f815..2fe4dda 100644
--- a/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/InsertTest.java
+++ b/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/InsertTest.java
@@ -2,8 +2,8 @@
 
 import android.support.test.runner.AndroidJUnit4;
 
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResult;
-import com.pushtorefresh.storio.contentresolver.query.Query;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResult;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/QueryTest.java b/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/QueryTest.java
index f2bbeb4..d881292 100644
--- a/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/QueryTest.java
+++ b/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/QueryTest.java
@@ -4,8 +4,8 @@
 import android.support.annotation.NonNull;
 import android.support.test.runner.AndroidJUnit4;
 
-import com.pushtorefresh.storio.contentresolver.operation.get.DefaultGetResolver;
-import com.pushtorefresh.storio.contentresolver.query.Query;
+import com.pushtorefresh.storio.contentresolver.operations.get.DefaultGetResolver;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/TweetMeta.java b/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/TweetMeta.java
index ed0cc18..8d898bf 100644
--- a/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/TweetMeta.java
+++ b/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/TweetMeta.java
@@ -7,16 +7,16 @@
 import android.support.annotation.NonNull;
 
 import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.operation.delete.DefaultDeleteResolver;
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.contentresolver.operation.get.DefaultGetResolver;
-import com.pushtorefresh.storio.contentresolver.operation.get.GetResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.DefaultPutResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResult;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-import com.pushtorefresh.storio.contentresolver.query.InsertQuery;
-import com.pushtorefresh.storio.contentresolver.query.UpdateQuery;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DefaultDeleteResolver;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.contentresolver.operations.get.DefaultGetResolver;
+import com.pushtorefresh.storio.contentresolver.operations.get.GetResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.DefaultPutResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResult;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;
+import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;
 
 class TweetMeta {
 
diff --git a/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/UpdateTest.java b/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/UpdateTest.java
index ce7db3a..d31d416 100644
--- a/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/UpdateTest.java
+++ b/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/UpdateTest.java
@@ -2,8 +2,8 @@
 
 import android.support.test.runner.AndroidJUnit4;
 
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResult;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResults;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResult;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResults;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/UserMeta.java b/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/UserMeta.java
index 805f005..2e80564 100644
--- a/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/UserMeta.java
+++ b/storio-content-resolver/src/androidTest/java/com/pushtorefresh/storio/content_resolver/impl/UserMeta.java
@@ -7,16 +7,16 @@
 import android.support.annotation.NonNull;
 
 import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.operation.delete.DefaultDeleteResolver;
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.contentresolver.operation.get.DefaultGetResolver;
-import com.pushtorefresh.storio.contentresolver.operation.get.GetResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.DefaultPutResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResult;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-import com.pushtorefresh.storio.contentresolver.query.InsertQuery;
-import com.pushtorefresh.storio.contentresolver.query.UpdateQuery;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DefaultDeleteResolver;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.contentresolver.operations.get.DefaultGetResolver;
+import com.pushtorefresh.storio.contentresolver.operations.get.GetResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.DefaultPutResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResult;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;
+import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;
 
 class UserMeta {
 
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/ContentResolverTypeMapping.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/ContentResolverTypeMapping.java
index 4832975..3dc3750 100644
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/ContentResolverTypeMapping.java
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/ContentResolverTypeMapping.java
@@ -2,9 +2,9 @@
 
 import android.support.annotation.NonNull;
 
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.contentresolver.operation.get.GetResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResolver;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.contentresolver.operations.get.GetResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResolver;
 
 import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
 
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/StorIOContentResolver.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/StorIOContentResolver.java
index ca8402c..3d7ba68 100644
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/StorIOContentResolver.java
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/StorIOContentResolver.java
@@ -7,13 +7,13 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.WorkerThread;
 
-import com.pushtorefresh.storio.contentresolver.operation.delete.PreparedDelete;
-import com.pushtorefresh.storio.contentresolver.operation.get.PreparedGet;
-import com.pushtorefresh.storio.contentresolver.operation.put.PreparedPut;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-import com.pushtorefresh.storio.contentresolver.query.InsertQuery;
-import com.pushtorefresh.storio.contentresolver.query.Query;
-import com.pushtorefresh.storio.contentresolver.query.UpdateQuery;
+import com.pushtorefresh.storio.contentresolver.operations.delete.PreparedDelete;
+import com.pushtorefresh.storio.contentresolver.operations.get.PreparedGet;
+import com.pushtorefresh.storio.contentresolver.operations.put.PreparedPut;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
+import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;
 
 import java.util.Collections;
 import java.util.Set;
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/impl/DefaultStorIOContentResolver.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/impl/DefaultStorIOContentResolver.java
index a835cdb..e20cd76 100644
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/impl/DefaultStorIOContentResolver.java
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/impl/DefaultStorIOContentResolver.java
@@ -15,10 +15,10 @@
 import com.pushtorefresh.storio.contentresolver.Changes;
 import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
 import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-import com.pushtorefresh.storio.contentresolver.query.InsertQuery;
-import com.pushtorefresh.storio.contentresolver.query.Query;
-import com.pushtorefresh.storio.contentresolver.query.UpdateQuery;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
+import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;
 
 import java.util.HashMap;
 import java.util.Map;
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DefaultDeleteResolver.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DefaultDeleteResolver.java
deleted file mode 100644
index a8c2951..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DefaultDeleteResolver.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-
-/**
- * Default implementation of {@link DeleteResolver}.
- * <p/>
- * Simply redirects {@link DeleteQuery} to {@link StorIOContentResolver}.
- * <p/>
- * Instances of this class are thread-safe.
- */
-public abstract class DefaultDeleteResolver<T> extends DeleteResolver<T> {
-
-    /**
-     * Converts object of required type to {@link DeleteQuery}.
-     *
-     * @param object non-null object that should be converted to {@link DeleteQuery}.
-     * @return non-null {@link DeleteQuery}.
-     */
-    @NonNull
-    protected abstract DeleteQuery mapToDeleteQuery(@NonNull T object);
-
-    /**
-     * {@inheritDoc}
-     */
-    @NonNull
-    @Override
-    public DeleteResult performDelete(@NonNull StorIOContentResolver storIOContentResolver, @NonNull T object) {
-        final DeleteQuery deleteQuery = mapToDeleteQuery(object);
-        final int numberOfRowsDeleted = storIOContentResolver.internal().delete(deleteQuery);
-        return DeleteResult.newInstance(numberOfRowsDeleted, deleteQuery.uri());
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResolver.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResolver.java
deleted file mode 100644
index e78b1f1..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResolver.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-
-/**
- * Defines behavior Delete Operation behavior.
- */
-public abstract class DeleteResolver<T> {
-
-    /**
-     * Performs Delete Operation.
-     *
-     * @param storIOContentResolver instance of {@link StorIOContentResolver}.
-     * @param object                non-null object that should be deleted.
-     * @return non-null result of Delete Operation.
-     */
-    @NonNull
-    public abstract DeleteResult performDelete(@NonNull StorIOContentResolver storIOContentResolver, @NonNull T object);
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResult.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResult.java
deleted file mode 100644
index d850480..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResult.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import android.net.Uri;
-import android.support.annotation.NonNull;
-
-import java.util.Collections;
-import java.util.Set;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-
-/**
- * Immutable container for results of Delete Operation.
- * <p/>
- * Instances of this class are Immutable.
- */
-public final class DeleteResult {
-
-    private final int numberOfRowsDeleted;
-
-    @NonNull
-    private final Set<Uri> affectedUris;
-
-    private DeleteResult(int numberOfRowsDeleted, @NonNull Set<Uri> affectedUris) {
-        this.numberOfRowsDeleted = numberOfRowsDeleted;
-        this.affectedUris = Collections.unmodifiableSet(affectedUris);
-    }
-
-    /**
-     * Creates new instance of immutable container for results of Delete Operation.
-     *
-     * @param numberOfRowsDeleted number of rows that were deleted.
-     * @param affectedUris        non-null set of Uris that wer affected.
-     * @return new instance of immutable container for results of Delete Operation.
-     */
-    @NonNull
-    public static DeleteResult newInstance(int numberOfRowsDeleted, @NonNull Set<Uri> affectedUris) {
-        checkNotNull(affectedUris, "Please specify affected Uris");
-        return new DeleteResult(numberOfRowsDeleted, affectedUris);
-    }
-
-    /**
-     * Creates new instance of immutable container for results of Delete Operation.
-     *
-     * @param numberOfRowsDeleted number of rows that were deleted.
-     * @param affectedUri         non-null Uri that was affected.
-     * @return new instance of immutable container for results of Delete Operation.
-     */
-    @NonNull
-    public static DeleteResult newInstance(int numberOfRowsDeleted, @NonNull Uri affectedUri) {
-        checkNotNull(affectedUri, "Please specify affected Uri");
-        return new DeleteResult(numberOfRowsDeleted, Collections.singleton(affectedUri));
-    }
-
-    /**
-     * Gets number of rows that were deleted.
-     *
-     * @return number of rows that were deleted.
-     */
-    public int numberOfRowsDeleted() {
-        return numberOfRowsDeleted;
-    }
-
-    /**
-     * Gets immutable set of affected Uris.
-     *
-     * @return affected Uris.
-     */
-    @NonNull
-    public Set<Uri> affectedUris() {
-        return affectedUris;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        DeleteResult that = (DeleteResult) o;
-
-        if (numberOfRowsDeleted != that.numberOfRowsDeleted) return false;
-        return affectedUris.equals(that.affectedUris);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = numberOfRowsDeleted;
-        result = 31 * result + affectedUris.hashCode();
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "DeleteResult{" +
-                "numberOfRowsDeleted=" + numberOfRowsDeleted +
-                ", affectedUris=" + affectedUris +
-                '}';
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResults.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResults.java
deleted file mode 100644
index 9956b61..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResults.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import android.support.annotation.NonNull;
-
-import java.util.Collections;
-import java.util.Map;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-
-/**
- * Immutable container for multiple results of Delete Operation.
- * <p/>
- * Instances of this class are immutable.
- */
-public final class DeleteResults<T> {
-
-    @NonNull
-    private final Map<T, DeleteResult> results;
-
-    private DeleteResults(@NonNull Map<T, DeleteResult> results) {
-        this.results = Collections.unmodifiableMap(results);
-    }
-
-    @NonNull
-    public static <T> DeleteResults<T> newInstance(@NonNull Map<T, DeleteResult> results) {
-        checkNotNull(results, "Please specify delete results map");
-        return new DeleteResults<T>(results);
-    }
-
-    /**
-     * Gets immutable Map of pairs (object, DeleteResult).
-     *
-     * @return immutable Map of pairs (object, DeleteResult).
-     */
-    @NonNull
-    public Map<T, DeleteResult> results() {
-        return results;
-    }
-
-    /**
-     * Checks whether particular object was deleted.
-     *
-     * @param object object to check.
-     * @return true if object was deleted, false otherwise.
-     */
-    public boolean wasDeleted(@NonNull T object) {
-        return results.containsKey(object);
-    }
-
-    /**
-     * Checks whether particular object was NOT deleted.
-     *
-     * @param object object to check.
-     * @return true if object was NOT deleter, false if it was deleted.
-     */
-    public boolean wasNotDeleted(@NonNull T object) {
-        return !results.containsKey(object);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        DeleteResults<?> that = (DeleteResults<?>) o;
-
-        return results.equals(that.results);
-    }
-
-    @Override
-    public int hashCode() {
-        return results.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        return "DeleteResults{" +
-                "results=" + results +
-                '}';
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDelete.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDelete.java
deleted file mode 100644
index a5db69f..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDelete.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-import com.pushtorefresh.storio.operation.PreparedOperation;
-
-import java.util.Collection;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-
-/**
- * Prepared Delete Operation for {@link StorIOContentResolver}.
- *
- * @param <Result> type of result of Delete Operation.
- */
-public abstract class PreparedDelete<Result> implements PreparedOperation<Result> {
-
-    @NonNull
-    protected final StorIOContentResolver storIOContentResolver;
-
-    PreparedDelete(@NonNull StorIOContentResolver storIOContentResolver) {
-        this.storIOContentResolver = storIOContentResolver;
-    }
-
-    /**
-     * Builder for {@link PreparedDelete}.
-     */
-    public static final class Builder {
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        /**
-         * Creates new builder for {@link PreparedDelete}.
-         *
-         * @param storIOContentResolver non-null instance of {@link StorIOContentResolver}.
-         */
-        public Builder(@NonNull StorIOContentResolver storIOContentResolver) {
-            checkNotNull(storIOContentResolver, "Please specify StorIOContentResolver");
-            this.storIOContentResolver = storIOContentResolver;
-        }
-
-        /**
-         * Creates builder for {@link PreparedDeleteByQuery}.
-         *
-         * @param deleteQuery non-null delete query.
-         * @return builder for {@link PreparedDeleteByQuery}.
-         */
-        @NonNull
-        public PreparedDeleteByQuery.Builder byQuery(@NonNull DeleteQuery deleteQuery) {
-            return new PreparedDeleteByQuery.Builder(storIOContentResolver, deleteQuery);
-        }
-
-        /**
-         * Creates builder for {@link PreparedDeleteCollectionOfObjects}.
-         *
-         * @param objects non-null collection of objects to delete.
-         * @param <T>     type of objects.
-         * @return builder for {@link PreparedDeleteCollectionOfObjects}.
-         */
-        @NonNull
-        public <T> PreparedDeleteCollectionOfObjects.Builder<T> objects(@NonNull Collection<T> objects) {
-            return new PreparedDeleteCollectionOfObjects.Builder<T>(storIOContentResolver, objects);
-        }
-
-        /**
-         * Creates builder for {@link PreparedDeleteObject}.
-         *
-         * @param object non-null object to delete.
-         * @param <T>    type of object.
-         * @return builder for {@link PreparedDeleteObject}.
-         */
-        @NonNull
-        public <T> PreparedDeleteObject.Builder<T> object(@NonNull T object) {
-            return new PreparedDeleteObject.Builder<T>(storIOContentResolver, object);
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteByQuery.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteByQuery.java
deleted file mode 100644
index e12ea9d..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteByQuery.java
+++ /dev/null
@@ -1,146 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Delete Operation for
- * {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver}.
- */
-public final class PreparedDeleteByQuery extends PreparedDelete<DeleteResult> {
-
-    @NonNull
-    private final DeleteQuery deleteQuery;
-
-    @NonNull
-    private final DeleteResolver<DeleteQuery> deleteResolver;
-
-    PreparedDeleteByQuery(@NonNull StorIOContentResolver storIOContentResolver,
-                          @NonNull DeleteQuery deleteQuery,
-                          @NonNull DeleteResolver<DeleteQuery> deleteResolver) {
-        super(storIOContentResolver);
-        this.deleteQuery = deleteQuery;
-        this.deleteResolver = deleteResolver;
-    }
-
-    /**
-     * Executes Delete Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null result of Delete Operation.
-     */
-    @WorkerThread
-    @NonNull
-    @Override
-    public DeleteResult executeAsBlocking() {
-        return deleteResolver.performDelete(storIOContentResolver, deleteQuery);
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Delete Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * delete only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Delete Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<DeleteResult> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedDeleteByQuery}.
-     */
-    public static final class Builder {
-
-        private static final DeleteResolver<DeleteQuery> STANDARD_DELETE_RESOLVER = new DefaultDeleteResolver<DeleteQuery>() {
-            @NonNull
-            @Override
-            protected DeleteQuery mapToDeleteQuery(@NonNull DeleteQuery deleteQuery) {
-                return deleteQuery; // easy
-            }
-        };
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        @NonNull
-        private final DeleteQuery deleteQuery;
-
-        private DeleteResolver<DeleteQuery> deleteResolver;
-
-        /**
-         * Creates builder for {@link PreparedDeleteByQuery}.
-         *
-         * @param storIOContentResolver non-null instance of {@link StorIOContentResolver}.
-         * @param deleteQuery           non-null instance of {@link DeleteQuery}.
-         */
-        public Builder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull DeleteQuery deleteQuery) {
-            checkNotNull(storIOContentResolver, "Please specify StorIOContentResolver");
-            checkNotNull(deleteQuery, "Please specify delete query");
-
-            this.storIOContentResolver = storIOContentResolver;
-            this.deleteQuery = deleteQuery;
-        }
-
-        /**
-         * Optional: Specifies resolver for Delete Operation.
-         * Allows you to customise behavior of Delete Operation.
-         * <p/>
-         * If no value will be set, builder will use Delete Resolver
-         * that simply redirects query to {@link StorIOContentResolver}.
-         *
-         * @param deleteResolver nullable resolver for Delete Operation.
-         * @return builder.
-         */
-        @NonNull
-        public Builder withDeleteResolver(@Nullable DeleteResolver<DeleteQuery> deleteResolver) {
-            this.deleteResolver = deleteResolver;
-            return this;
-        }
-
-        /**
-         * Builds instance of {@link PreparedDeleteByQuery}.
-         *
-         * @return instance of {@link PreparedDeleteByQuery}.
-         */
-        @NonNull
-        public PreparedDeleteByQuery prepare() {
-            if (deleteResolver == null) {
-                deleteResolver = STANDARD_DELETE_RESOLVER;
-            }
-
-            return new PreparedDeleteByQuery(
-                    storIOContentResolver,
-                    deleteQuery,
-                    deleteResolver
-            );
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteCollectionOfObjects.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteCollectionOfObjects.java
deleted file mode 100644
index 1411166..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteCollectionOfObjects.java
+++ /dev/null
@@ -1,187 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-
-import java.util.AbstractMap.SimpleImmutableEntry;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Delete Operation for {@link StorIOContentResolver}.
- *
- * @param <T> type of objects to delete.
- */
-public final class PreparedDeleteCollectionOfObjects<T> extends PreparedDelete<DeleteResults<T>> {
-
-    @NonNull
-    private final Collection<T> objects;
-
-    @Nullable
-    private final DeleteResolver<T> explicitDeleteResolver;
-
-    PreparedDeleteCollectionOfObjects(@NonNull StorIOContentResolver storIOContentResolver,
-                                      @NonNull Collection<T> objects,
-                                      @Nullable DeleteResolver<T> explicitDeleteResolver) {
-        super(storIOContentResolver);
-        this.objects = objects;
-        this.explicitDeleteResolver = explicitDeleteResolver;
-    }
-
-    /**
-     * Executes Delete Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null results of Delete Operation.
-     */
-    @SuppressWarnings("unchecked")
-    @WorkerThread
-    @NonNull
-    @Override
-    public DeleteResults<T> executeAsBlocking() {
-        final StorIOContentResolver.Internal internal = storIOContentResolver.internal();
-
-        // Nullable
-        final List<SimpleImmutableEntry> objectsAndDeleteResolvers;
-
-        if (explicitDeleteResolver != null) {
-            objectsAndDeleteResolvers = null;
-        } else {
-            objectsAndDeleteResolvers = new ArrayList<SimpleImmutableEntry>(objects.size());
-
-            for (final T object : objects) {
-                final ContentResolverTypeMapping<T> typeMapping
-                        = (ContentResolverTypeMapping<T>) internal.typeMapping(object.getClass());
-
-                if (typeMapping == null) {
-                    throw new IllegalStateException("One of the objects from the collection does not have type mapping: " +
-                            "object = " + object + ", object.class = " + object.getClass() + "," +
-                            "ContentProvider was not affected by this operation, please add type mapping for this type");
-                }
-
-                objectsAndDeleteResolvers.add(new SimpleImmutableEntry(
-                        object,
-                        typeMapping.deleteResolver()
-                ));
-            }
-        }
-
-        final Map<T, DeleteResult> results = new HashMap<T, DeleteResult>(objects.size());
-
-        if (explicitDeleteResolver != null) {
-            for (final T object : objects) {
-                final DeleteResult deleteResult = explicitDeleteResolver.performDelete(storIOContentResolver, object);
-                results.put(object, deleteResult);
-            }
-        } else {
-            for (final SimpleImmutableEntry<T, DeleteResolver<T>> objectAndDeleteResolver : objectsAndDeleteResolvers) {
-                final T object = objectAndDeleteResolver.getKey();
-                final DeleteResolver<T> deleteResolver = objectAndDeleteResolver.getValue();
-
-                final DeleteResult deleteResult = deleteResolver.performDelete(storIOContentResolver, object);
-                results.put(object, deleteResult);
-            }
-        }
-
-        return DeleteResults.newInstance(results);
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Delete Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * delete only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Delete Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<DeleteResults<T>> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedDeleteCollectionOfObjects}.
-     *
-     * @param <T> type of objects.
-     */
-    public static final class Builder<T> {
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        @NonNull
-        private final Collection<T> objects;
-
-        @Nullable
-        private DeleteResolver<T> deleteResolver;
-
-        /**
-         * Creates builder for {@link PreparedDeleteCollectionOfObjects}.
-         *
-         * @param storIOContentResolver non-null instance of {@link StorIOContentResolver}.
-         * @param objects               non-null collection of objects to delete.
-         */
-        public Builder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Collection<T> objects) {
-            this.storIOContentResolver = storIOContentResolver;
-            this.objects = objects;
-        }
-
-        /**
-         * Optional: Specifies resolver for Delete Operation.
-         * Allows you to customise behavior of Delete Operation.
-         * <p/>
-         * Can be set via {@link ContentResolverTypeMapping},
-         * If value is not set via {@link ContentResolverTypeMapping}
-         * or explicitly -> exception will be thrown.
-         *
-         * @param deleteResolver nullable resolver for Delete Operation.
-         * @return builder.
-         */
-        @NonNull
-        public Builder<T> withDeleteResolver(@Nullable DeleteResolver<T> deleteResolver) {
-            this.deleteResolver = deleteResolver;
-            return this;
-        }
-
-        /**
-         * Builds instance of {@link PreparedDeleteCollectionOfObjects}.
-         *
-         * @return instance of {@link PreparedDeleteCollectionOfObjects}.
-         */
-        @NonNull
-        public PreparedDeleteCollectionOfObjects<T> prepare() {
-            return new PreparedDeleteCollectionOfObjects<T>(
-                    storIOContentResolver,
-                    objects,
-                    deleteResolver
-            );
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteObject.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteObject.java
deleted file mode 100644
index 2d70f8d..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteObject.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Delete Operation for
- * {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver}.
- */
-public final class PreparedDeleteObject<T> extends PreparedDelete<DeleteResult> {
-
-    @NonNull
-    private final T object;
-
-    @Nullable
-    private final DeleteResolver<T> explicitDeleteResolver;
-
-    PreparedDeleteObject(@NonNull StorIOContentResolver storIOContentResolver,
-                         @NonNull T object,
-                         @Nullable DeleteResolver<T> explicitDeleteResolver) {
-        super(storIOContentResolver);
-        this.object = object;
-        this.explicitDeleteResolver = explicitDeleteResolver;
-    }
-
-    /**
-     * Executes Delete Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null result of Delete Operation.
-     */
-    @SuppressWarnings("unchecked")
-    @WorkerThread
-    @NonNull
-    @Override
-    public DeleteResult executeAsBlocking() {
-        final DeleteResolver<T> deleteResolver;
-
-        if (explicitDeleteResolver != null) {
-            deleteResolver = explicitDeleteResolver;
-        } else {
-            final ContentResolverTypeMapping<T> typeMapping
-                    = storIOContentResolver.internal().typeMapping((Class<T>) object.getClass());
-
-            if (typeMapping == null) {
-                throw new IllegalStateException("Object does not have type mapping: " +
-                        "object = " + object + ", object.class = " + object.getClass() + "," +
-                        "ContentProvider was not affected by this operation, please add type mapping for this type");
-            }
-
-            deleteResolver = typeMapping.deleteResolver();
-        }
-
-        return deleteResolver.performDelete(storIOContentResolver, object);
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Delete Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * delete only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Delete Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<DeleteResult> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedDeleteObject}.
-     *
-     * @param <T> type of object to delete.
-     */
-    public static final class Builder<T> {
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        @NonNull
-        private final T object;
-
-        private DeleteResolver<T> deleteResolver;
-
-        /**
-         * Creates builder for {@link PreparedDeleteObject}.
-         *
-         * @param storIOContentResolver non-null instance of {@link StorIOContentResolver}.
-         * @param object                non-null object that should be deleted.
-         */
-        public Builder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull T object) {
-            checkNotNull(storIOContentResolver, "Please specify StorIOContentResolver");
-            checkNotNull(object, "Please specify object to delete");
-
-            this.storIOContentResolver = storIOContentResolver;
-            this.object = object;
-        }
-
-        /**
-         * Optional: Specifies resolver for Delete Operation.
-         * Allows you to customise behavior of Delete Operation.
-         * <p/>
-         * Can be set via {@link ContentResolverTypeMapping},
-         * If value is not set via {@link ContentResolverTypeMapping}
-         * or explicitly -> exception will be thrown.
-         *
-         * @param deleteResolver resolver for Delete Operation.
-         * @return builder.
-         */
-        @NonNull
-        public Builder<T> withDeleteResolver(@NonNull DeleteResolver<T> deleteResolver) {
-            this.deleteResolver = deleteResolver;
-            return this;
-        }
-
-        /**
-         * Builds new instance of {@link PreparedDeleteObject}.
-         *
-         * @return new instance of {@link PreparedDeleteObject}.
-         */
-        @NonNull
-        public PreparedDeleteObject<T> prepare() {
-            return new PreparedDeleteObject<T>(
-                    storIOContentResolver,
-                    object,
-                    deleteResolver
-            );
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/DefaultGetResolver.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/DefaultGetResolver.java
deleted file mode 100644
index a91ee1f..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/DefaultGetResolver.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.get;
-
-import android.database.Cursor;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.Query;
-
-/**
- * Default implementation of {@link GetResolver}, thread-safe.
- */
-public abstract class DefaultGetResolver<T> extends GetResolver<T> {
-
-    /**
-     * {@inheritDoc}
-     */
-    @NonNull
-    @Override
-    public Cursor performGet(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Query query) {
-        return storIOContentResolver.internal().query(query);
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/GetResolver.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/GetResolver.java
deleted file mode 100644
index 2239c39..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/GetResolver.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.get;
-
-import android.database.Cursor;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.Query;
-
-/**
- * Defines behavior of Get Operation.
- */
-public abstract class GetResolver<T> {
-
-    /**
-     * Converts {@link Cursor} with already set position to object of required type.
-     *
-     * @param cursor not closed {@link Cursor} with already set position
-     *               that should be parsed and converted to object of required type.
-     * @return non-null object of required type with data parsed from passed {@link Cursor}.
-     */
-    @NonNull
-    public abstract T mapFromCursor(@NonNull Cursor cursor);
-
-    /**
-     * Performs Get Operation
-     *
-     * @param storIOContentResolver non-null instance of {@link StorIOContentResolver}.
-     * @param query                 non-null query that should be processed.
-     * @return non-null, not closed {@link Cursor} that can be empty or contain
-     * data with results of Get Operation.
-     * <p>
-     * Notice, that {@link android.content.ContentProvider} can return null {@link Cursor}
-     * from {@link android.content.ContentProvider#query(android.net.Uri, String[], String, String[], String)}
-     * But null {@link Cursor} is not very great thing to work with,
-     * so if {@link android.content.ContentProvider} returns null,
-     * {@link StorIOContentResolver} will return empty cursor.
-     */
-    @NonNull
-    public abstract Cursor performGet(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Query query);
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGet.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGet.java
deleted file mode 100644
index 1c52f92..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGet.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.get;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.operation.PreparedOperation;
-
-/**
- * Represents Get Operation for {@link StorIOContentResolver}.
- *
- * @param <Result> type of result.
- */
-public abstract class PreparedGet<Result> implements PreparedOperation<Result> {
-
-    @NonNull
-    protected final StorIOContentResolver storIOContentResolver;
-
-    PreparedGet(@NonNull StorIOContentResolver storIOContentResolver) {
-        this.storIOContentResolver = storIOContentResolver;
-    }
-
-    /**
-     * Builder for {@link PreparedGet}.
-     */
-    public final static class Builder {
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        public Builder(@NonNull StorIOContentResolver storIOContentResolver) {
-            this.storIOContentResolver = storIOContentResolver;
-        }
-
-        /**
-         * Returns builder for Get Operation that returns result as {@link android.database.Cursor}.
-         *
-         * @return builder for Get Operation that returns result as {@link android.database.Cursor}.
-         */
-        @NonNull
-        public PreparedGetCursor.Builder cursor() {
-            return new PreparedGetCursor.Builder(storIOContentResolver);
-        }
-
-        /**
-         * Returns builder for Get Operation that returns result as {@link java.util.List} of items.
-         *
-         * @param type type of items.
-         * @param <T>  type of items.
-         * @return builder for Get Operation that returns result as {@link java.util.List} of items.
-         */
-        @NonNull
-        public <T> PreparedGetListOfObjects.Builder<T> listOfObjects(@NonNull Class<T> type) {
-            return new PreparedGetListOfObjects.Builder<T>(storIOContentResolver, type);
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetCursor.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetCursor.java
deleted file mode 100644
index 3b1590f..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetCursor.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.get;
-
-import android.database.Cursor;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.Query;
-import com.pushtorefresh.storio.operation.internal.MapSomethingToExecuteAsBlocking;
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Represents Get Operation for {@link StorIOContentResolver}
- * which performs query that retrieves data as {@link Cursor}.
- * from {@link android.content.ContentProvider}.
- */
-public final class PreparedGetCursor extends PreparedGet<Cursor> {
-
-    @NonNull
-    private final Query query;
-
-    @NonNull
-    private final GetResolver<Cursor> getResolver;
-
-    PreparedGetCursor(@NonNull StorIOContentResolver storIOContentResolver,
-                      @NonNull GetResolver<Cursor> getResolver,
-                      @NonNull Query query) {
-        super(storIOContentResolver);
-        this.query = query;
-        this.getResolver = getResolver;
-    }
-
-    /**
-     * Executes Get Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null {@link Cursor}, can be empty.
-     */
-    @WorkerThread
-    @NonNull
-    @Override
-    public Cursor executeAsBlocking() {
-        return getResolver.performGet(storIOContentResolver, query);
-    }
-
-    /**
-     * Creates "Hot" {@link Observable} which will be subscribed to changes of {@link #query} Uri
-     * and will emit result each time change occurs.
-     * <p/>
-     * First result will be emitted immediately after subscription,
-     * other emissions will occur only if changes of {@link #query} Uri will occur.
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     * <p/>
-     * Please don't forget to unsubscribe from this {@link Observable} because
-     * it's "Hot" and endless.
-     *
-     * @return non-null {@link Observable} which will emit non-null
-     * list with mapped results and will be subscribed to changes of {@link #query} Uri.
-     */
-    @NonNull
-    @Override
-    public Observable<Cursor> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return storIOContentResolver
-                .observeChangesOfUri(query.uri()) // each change triggers executeAsBlocking
-                .map(MapSomethingToExecuteAsBlocking.newInstance(this))
-                .startWith(Observable.create(OnSubscribeExecuteAsBlocking.newInstance(this))) // start stream with first query result
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedGetCursor}.
-     * <p/>
-     * Required: You should specify query see {@link #withQuery(Query)}.
-     */
-    public static final class Builder {
-
-        @NonNull
-        final StorIOContentResolver storIOContentResolver;
-
-        public Builder(@NonNull StorIOContentResolver storIOContentResolver) {
-            this.storIOContentResolver = storIOContentResolver;
-        }
-
-        /**
-         * Required: Specifies {@link Query} for Get Operation.
-         *
-         * @param query query.
-         * @return builder.
-         */
-        @NonNull
-        public CompleteBuilder withQuery(@NonNull Query query) {
-            checkNotNull(query, "Please specify Query");
-            return new CompleteBuilder(storIOContentResolver, query);
-        }
-    }
-
-    /**
-     * Compile-time safe part of builder for {@link PreparedGetCursor}.
-     */
-    public static final class CompleteBuilder {
-
-        private static final GetResolver<Cursor> STANDARD_GET_RESOLVER = new DefaultGetResolver<Cursor>() {
-            @NonNull
-            @Override
-            public Cursor mapFromCursor(@NonNull Cursor cursor) {
-                return cursor; // easy
-            }
-        };
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        @NonNull
-        private final Query query;
-
-        private GetResolver<Cursor> getResolver;
-
-        CompleteBuilder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Query query) {
-            this.storIOContentResolver = storIOContentResolver;
-            this.query = query;
-        }
-
-        /**
-         * Optional: Specifies {@link GetResolver} for Get Operation
-         * which allows you to customize behavior of Get Operation.
-         * <p/>
-         * If no value will be set, builder will use resolver that
-         * simply redirects query to {@link StorIOContentResolver}.
-         *
-         * @param getResolver GetResolver.
-         * @return builder.
-         */
-        @NonNull
-        public CompleteBuilder withGetResolver(@Nullable GetResolver<Cursor> getResolver) {
-            this.getResolver = getResolver;
-            return this;
-        }
-
-        /**
-         * Prepares Get Operation.
-         *
-         * @return {@link PreparedGetCursor} instance.
-         */
-        @NonNull
-        public PreparedGetCursor prepare() {
-            if (getResolver == null) {
-                getResolver = STANDARD_GET_RESOLVER;
-            }
-
-            return new PreparedGetCursor(
-                    storIOContentResolver,
-                    getResolver,
-                    query
-            );
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetListOfObjects.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetListOfObjects.java
deleted file mode 100644
index b32920e..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetListOfObjects.java
+++ /dev/null
@@ -1,221 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.get;
-
-import android.database.Cursor;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.Query;
-import com.pushtorefresh.storio.operation.internal.MapSomethingToExecuteAsBlocking;
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-import static java.util.Collections.EMPTY_LIST;
-import static java.util.Collections.unmodifiableList;
-
-/**
- * Represents Get Operation for {@link StorIOContentResolver}
- * which performs query that retrieves data as list of objects
- * from {@link android.content.ContentProvider}.
- *
- * @param <T> type of result.
- */
-public final class PreparedGetListOfObjects<T> extends PreparedGet<List<T>> {
-
-    @NonNull
-    private final Class<T> type;
-
-    @NonNull
-    private final Query query;
-
-    @Nullable
-    private final GetResolver<T> explicitGetResolver;
-
-    PreparedGetListOfObjects(@NonNull StorIOContentResolver storIOContentResolver,
-                             @NonNull Class<T> type,
-                             @NonNull Query query,
-                             @Nullable GetResolver<T> explicitGetResolver) {
-        super(storIOContentResolver);
-        this.type = type;
-        this.query = query;
-        this.explicitGetResolver = explicitGetResolver;
-    }
-
-    /**
-     * Executes Prepared Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null, immutable {@link List} with mapped results, list can be empty.
-     */
-    @WorkerThread
-    @SuppressWarnings("unchecked") // for empty list
-    @NonNull
-    @Override
-    public List<T> executeAsBlocking() {
-        final GetResolver<T> getResolver;
-
-        if (explicitGetResolver != null) {
-            getResolver = explicitGetResolver;
-        } else {
-            final ContentResolverTypeMapping<T> typeMapping = storIOContentResolver.internal().typeMapping(type);
-
-            if (typeMapping == null) {
-                throw new IllegalStateException("This type does not have type mapping: " +
-                        "type = " + type + "," +
-                        "ContentProvider was not touched by this operation, please add type mapping for this type");
-            }
-
-            getResolver = typeMapping.getResolver();
-        }
-
-        final Cursor cursor = getResolver.performGet(storIOContentResolver, query);
-
-        try {
-            final int count = cursor.getCount();
-
-            if (count == 0) {
-                return EMPTY_LIST; // it's immutable
-            } else {
-                final List<T> list = new ArrayList<T>(count);
-
-                while (cursor.moveToNext()) {
-                    list.add(getResolver.mapFromCursor(cursor));
-                }
-
-                return unmodifiableList(list);
-            }
-        } finally {
-            cursor.close();
-        }
-    }
-
-    /**
-     * Creates "Hot" {@link Observable} which will be subscribed to changes of {@link #query} Uri
-     * and will emit result each time change occurs.
-     * <p/>
-     * First result will be emitted immediately after subscription,
-     * other emissions will occur only if changes of {@link #query} Uri will occur.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     * <p/>
-     * Please don't forget to unsubscribe from this {@link Observable}
-     * because it's "Hot" and endless.
-     *
-     * @return non-null {@link Observable} which will emit non-null, immutable
-     * {@link List} with mapped results and will be subscribed to changes of {@link #query} Uri,
-     * list can be empty.
-     */
-    @NonNull
-    @Override
-    public Observable<List<T>> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return storIOContentResolver
-                .observeChangesOfUri(query.uri()) // each change triggers executeAsBlocking
-                .map(MapSomethingToExecuteAsBlocking.newInstance(this))
-                .startWith(Observable.create(OnSubscribeExecuteAsBlocking.newInstance(this))) // start stream with first query result
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Compile-time safe part of builder for {@link PreparedGetListOfObjects}.
-     *
-     * @param <T> type of objects for query.
-     */
-    public static final class Builder<T> {
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        @NonNull
-        private final Class<T> type;
-
-        public Builder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Class<T> type) {
-            this.storIOContentResolver = storIOContentResolver;
-            this.type = type;
-        }
-
-        /**
-         * Required: Specifies {@link Query} for Get Operation.
-         *
-         * @param query query.
-         * @return builder.
-         */
-        @NonNull
-        public CompleteBuilder<T> withQuery(@NonNull Query query) {
-            checkNotNull(query, "Please specify query");
-            return new CompleteBuilder<T>(storIOContentResolver, type, query);
-        }
-    }
-
-    /**
-     * Compile-time safe part of builder for {@link PreparedGetListOfObjects}.
-     *
-     * @param <T> type of objects for query.
-     */
-    public static final class CompleteBuilder<T> {
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        @NonNull
-        private final Class<T> type;
-
-        @NonNull
-        private final Query query;
-
-        private GetResolver<T> getResolver;
-
-        CompleteBuilder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Class<T> type, @NonNull Query query) {
-            this.storIOContentResolver = storIOContentResolver;
-            this.type = type;
-            this.query = query;
-        }
-
-        /**
-         * Optional: Specifies {@link GetResolver} for Get Operation
-         * which allows you to customize behavior of Get Operation.
-         * <p/>
-         * Can be set via {@link ContentResolverTypeMapping},
-         * If value is not set via {@link ContentResolverTypeMapping} -> exception will be thrown.
-         *
-         * @param getResolver GetResolver.
-         * @return builder.
-         */
-        @NonNull
-        public CompleteBuilder<T> withGetResolver(@Nullable GetResolver<T> getResolver) {
-            this.getResolver = getResolver;
-            return this;
-        }
-
-        /**
-         * Builds new instance of {@link PreparedGetListOfObjects}.
-         *
-         * @return new instance of {@link PreparedGetListOfObjects}.
-         */
-        @NonNull
-        public PreparedGetListOfObjects<T> prepare() {
-            return new PreparedGetListOfObjects<T>(
-                    storIOContentResolver,
-                    type,
-                    query,
-                    getResolver
-            );
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/DefaultPutResolver.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/DefaultPutResolver.java
deleted file mode 100644
index 30ce084..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/DefaultPutResolver.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.InsertQuery;
-import com.pushtorefresh.storio.contentresolver.query.Query;
-import com.pushtorefresh.storio.contentresolver.query.UpdateQuery;
-
-import static com.pushtorefresh.storio.internal.Queries.nullableArrayOfStrings;
-import static com.pushtorefresh.storio.internal.Queries.nullableString;
-
-/**
- * Default thread-safe implementation of {@link PutResolver}.
- *
- * @param <T> type of objects to put.
- */
-public abstract class DefaultPutResolver<T> extends PutResolver<T> {
-
-    /**
-     * Converts object of required type to {@link InsertQuery}.
-     *
-     * @param object non-null object that should be converted to {@link InsertQuery}.
-     * @return non-null {@link InsertQuery}.
-     */
-    @NonNull
-    protected abstract InsertQuery mapToInsertQuery(@NonNull T object);
-
-    /**
-     * Converts object of required type to {@link UpdateQuery}.
-     *
-     * @param object non-null object that should be converted to {@link UpdateQuery}.
-     * @return non-null {@link UpdateQuery}.
-     */
-    @NonNull
-    protected abstract UpdateQuery mapToUpdateQuery(@NonNull T object);
-
-    /**
-     * Converts object of required type to {@link ContentValues}.
-     *
-     * @param object non-null object that should be converted to {@link ContentValues}.
-     * @return non-null {@link ContentValues}.
-     */
-    @NonNull
-    protected abstract ContentValues mapToContentValues(@NonNull T object);
-
-    /**
-     * {@inheritDoc}
-     */
-    @NonNull
-    @Override
-    public PutResult performPut(@NonNull StorIOContentResolver storIOContentResolver, @NonNull T object) {
-        final UpdateQuery updateQuery = mapToUpdateQuery(object);
-
-        final Query query = Query.builder()
-                .uri(updateQuery.uri())
-                .where(nullableString(updateQuery.where()))
-                .whereArgs((Object[]) nullableArrayOfStrings(updateQuery.whereArgs()))
-                .build();
-
-        final Cursor cursor = storIOContentResolver.internal().query(query);
-
-        try {
-            final ContentValues contentValues = mapToContentValues(object);
-
-            if (cursor == null || cursor.getCount() == 0) {
-                final InsertQuery insertQuery = mapToInsertQuery(object);
-                final Uri insertedUri = storIOContentResolver.internal().insert(insertQuery, contentValues);
-                return PutResult.newInsertResult(insertedUri, insertQuery.uri());
-            } else {
-                final int numberOfRowsUpdated = storIOContentResolver.internal().update(updateQuery, contentValues);
-                return PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.uri());
-            }
-        } finally {
-            if (cursor != null) {
-                cursor.close();
-            }
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPut.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPut.java
deleted file mode 100644
index 0b28e64..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPut.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.content.ContentValues;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.operation.PreparedOperation;
-
-import java.util.Collection;
-
-/**
- * Represents an Operation for {@link StorIOContentResolver} which performs insert or update data
- * in {@link android.content.ContentProvider}.
- *
- */
-public abstract class PreparedPut<Result> implements PreparedOperation<Result> {
-
-    @NonNull
-    protected final StorIOContentResolver storIOContentResolver;
-
-    protected PreparedPut(@NonNull StorIOContentResolver storIOContentResolver) {
-        this.storIOContentResolver = storIOContentResolver;
-    }
-
-    /**
-     * Builder for {@link PreparedPut}.
-     */
-    public static final class Builder {
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        public Builder(@NonNull StorIOContentResolver storIOContentResolver) {
-            this.storIOContentResolver = storIOContentResolver;
-        }
-
-        /**
-         * Prepares Put Operation that should put one object.
-         *
-         * @param object object to put.
-         * @param <T>    type of object.
-         * @return builder for {@link PreparedPutObject}.
-         */
-        @NonNull
-        public <T> PreparedPutObject.Builder<T> object(@NonNull T object) {
-            return new PreparedPutObject.Builder<T>(storIOContentResolver, object);
-        }
-
-        /**
-         * Prepares Put Operation that should put multiple objects.
-         *
-         * @param objects objects to put.
-         * @param <T>     type of objects.
-         * @return builder for {@link PreparedPutCollectionOfObjects}.
-         */
-        @NonNull
-        public <T> PreparedPutCollectionOfObjects.Builder<T> objects(@NonNull Collection<T> objects) {
-            return new PreparedPutCollectionOfObjects.Builder<T>(storIOContentResolver, objects);
-        }
-
-        /**
-         * Prepares Put Operation that should put one instance of {@link ContentValues}.
-         *
-         * @param contentValues non-null content values to put.
-         * @return builder for {@link PreparedPutContentValues}.
-         */
-        @NonNull
-        public PreparedPutContentValues.Builder contentValues(@NonNull ContentValues contentValues) {
-            return new PreparedPutContentValues.Builder(storIOContentResolver, contentValues);
-        }
-
-        /**
-         * Prepares Put Operation that should put several instances of {@link ContentValues}.
-         *
-         * @param contentValues non-null collection of {@link ContentValues}.
-         * @return builder for {@link PreparedPutContentValuesIterable}.
-         */
-        @NonNull
-        public PreparedPutContentValuesIterable.Builder contentValues(@NonNull Iterable<ContentValues> contentValues) {
-            return new PreparedPutContentValuesIterable.Builder(storIOContentResolver, contentValues);
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutCollectionOfObjects.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutCollectionOfObjects.java
deleted file mode 100644
index 2bfdb5f..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutCollectionOfObjects.java
+++ /dev/null
@@ -1,182 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-
-import java.util.AbstractMap.SimpleImmutableEntry;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Put Operation for collection of objects.
- *
- * @param <T> type of objects.
- */
-public final class PreparedPutCollectionOfObjects<T> extends PreparedPut<PutResults<T>> {
-
-    @NonNull
-    private final Collection<T> objects;
-
-    @Nullable
-    private final PutResolver<T> explicitPutResolver;
-
-    PreparedPutCollectionOfObjects(@NonNull StorIOContentResolver storIOContentResolver,
-                                   @NonNull Collection<T> objects,
-                                   @Nullable PutResolver<T> explicitPutResolver) {
-        super(storIOContentResolver);
-        this.objects = objects;
-        this.explicitPutResolver = explicitPutResolver;
-    }
-
-    /**
-     * Executes Put Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null result of Put Operation.
-     */
-    @SuppressWarnings("unchecked")
-    @WorkerThread
-    @NonNull
-    @Override
-    public PutResults<T> executeAsBlocking() {
-        final StorIOContentResolver.Internal internal = storIOContentResolver.internal();
-
-        // Nullable
-        final List<SimpleImmutableEntry<T, PutResolver<T>>> objectsAndPutResolvers;
-
-        if (explicitPutResolver != null) {
-            objectsAndPutResolvers = null;
-        } else {
-            objectsAndPutResolvers = new ArrayList<SimpleImmutableEntry<T, PutResolver<T>>>(objects.size());
-
-            for (final T object : objects) {
-                final ContentResolverTypeMapping<T> typeMapping
-                        = (ContentResolverTypeMapping<T>) internal.typeMapping(object.getClass());
-
-                if (typeMapping == null) {
-                    throw new IllegalStateException("One of the objects from the collection does not have type mapping: " +
-                            "object = " + object + ", object.class = " + object.getClass() + "," +
-                            "ContentProvider was not affected by this operation, please add type mapping for this type");
-                }
-
-                objectsAndPutResolvers.add(new SimpleImmutableEntry<T, PutResolver<T>>(
-                        object,
-                        typeMapping.putResolver()
-                ));
-            }
-        }
-
-        final Map<T, PutResult> results = new HashMap<T, PutResult>(objects.size());
-
-        if (explicitPutResolver != null) {
-            for (final T object : objects) {
-                final PutResult putResult = explicitPutResolver.performPut(storIOContentResolver, object);
-                results.put(object, putResult);
-            }
-        } else {
-            for (final SimpleImmutableEntry<T, PutResolver<T>> objectAndPutResolver : objectsAndPutResolvers) {
-                final T object = objectAndPutResolver.getKey();
-                final PutResolver<T> putResolver = objectAndPutResolver.getValue();
-
-                final PutResult putResult = putResolver.performPut(storIOContentResolver, object);
-                results.put(object, putResult);
-            }
-        }
-
-        return PutResults.newInstance(results);
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Put Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * put only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Put Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<PutResults<T>> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedPutCollectionOfObjects}.
-     *
-     * @param <T> type of objects to put.
-     */
-    public static final class Builder<T> {
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        @NonNull
-        private final Collection<T> objects;
-
-        @Nullable
-        private PutResolver<T> putResolver;
-
-        public Builder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Collection<T> objects) {
-            this.storIOContentResolver = storIOContentResolver;
-            this.objects = objects;
-        }
-
-        /**
-         * Optional: Specifies resolver for Put Operation
-         * that should define behavior of Put Operation: insert or update
-         * of the objects.
-         * <p/>
-         * Can be set via {@link ContentResolverTypeMapping},
-         * If value is not set via {@link ContentResolverTypeMapping}
-         * or explicitly -> exception will be thrown.
-         *
-         * @param putResolver nullable resolver for Put Operation.
-         * @return builder.
-         */
-        @NonNull
-        public Builder<T> withPutResolver(@NonNull PutResolver<T> putResolver) {
-            this.putResolver = putResolver;
-            return this;
-        }
-
-        /**
-         * Builds new instance of {@link PreparedPutCollectionOfObjects}.
-         *
-         * @return new instance of {@link PreparedPutCollectionOfObjects}.
-         */
-        @NonNull
-        public PreparedPutCollectionOfObjects<T> prepare() {
-            return new PreparedPutCollectionOfObjects<T>(
-                    storIOContentResolver,
-                    objects,
-                    putResolver
-            );
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValues.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValues.java
deleted file mode 100644
index c2502b9..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValues.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.content.ContentValues;
-import android.support.annotation.NonNull;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Put Operation for {@link ContentValues}.
- */
-public final class PreparedPutContentValues extends PreparedPut<PutResult> {
-
-    @NonNull
-    private final ContentValues contentValues;
-
-    @NonNull
-    private final PutResolver<ContentValues> putResolver;
-
-    PreparedPutContentValues(@NonNull StorIOContentResolver storIOContentResolver,
-                             @NonNull PutResolver<ContentValues> putResolver,
-                             @NonNull ContentValues contentValues) {
-        super(storIOContentResolver);
-        this.contentValues = contentValues;
-        this.putResolver = putResolver;
-    }
-
-    /**
-     * Executes Put Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null result of Put Operation.
-     */
-    @WorkerThread
-    @NonNull
-    @Override
-    public PutResult executeAsBlocking() {
-        return putResolver.performPut(storIOContentResolver, contentValues);
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Put Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * put only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Put Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<PutResult> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedPutContentValues}.
-     * <p/>
-     * Required: You should specify put resolver see {@link #withPutResolver(PutResolver)}.
-     */
-    public static final class Builder {
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        @NonNull
-        private final ContentValues contentValues;
-
-        /**
-         * Creates builder for {@link PreparedPutContentValues}.
-         *
-         * @param storIOContentResolver instance of {@link StorIOContentResolver}.
-         * @param contentValues         some {@link ContentValues} to put.
-         */
-        public Builder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull ContentValues contentValues) {
-            checkNotNull(storIOContentResolver, "Please specify StorIOContentResolver");
-            checkNotNull(contentValues, "Please specify content values");
-
-            this.storIOContentResolver = storIOContentResolver;
-            this.contentValues = contentValues;
-        }
-
-        /**
-         * Required: Specifies resolver for Put Operation.
-         * that should define behavior of Put Operation: insert or update
-         * of the {@link ContentValues}.
-         *
-         * @param putResolver resolver for Put Operation.
-         * @return builder.
-         */
-        @NonNull
-        public CompleteBuilder withPutResolver(@NonNull PutResolver<ContentValues> putResolver) {
-            checkNotNull(putResolver, "Please specify PutResolver");
-            return new CompleteBuilder(storIOContentResolver, contentValues, putResolver);
-        }
-    }
-
-    /**
-     * Compile-time safe part of builder for {@link PreparedPutContentValues}.
-     */
-    public static final class CompleteBuilder {
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        @NonNull
-        private final ContentValues contentValues;
-
-        @NonNull
-        private final PutResolver<ContentValues> putResolver;
-
-        CompleteBuilder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull ContentValues contentValues, @NonNull PutResolver<ContentValues> putResolver) {
-            this.storIOContentResolver = storIOContentResolver;
-            this.contentValues = contentValues;
-            this.putResolver = putResolver;
-        }
-
-        /**
-         * Builds instance of {@link PreparedPutContentValues}.
-         *
-         * @return instance of {@link PreparedPutContentValues}.
-         */
-        @NonNull
-        public PreparedPutContentValues prepare() {
-            return new PreparedPutContentValues(
-                    storIOContentResolver,
-                    putResolver,
-                    contentValues
-            );
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValuesIterable.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValuesIterable.java
deleted file mode 100644
index ead317c..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValuesIterable.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.content.ContentValues;
-import android.support.annotation.NonNull;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Put Operation to perform put multiple {@link ContentValues}
- * into {@link StorIOContentResolver}.
- */
-public final class PreparedPutContentValuesIterable extends PreparedPut<PutResults<ContentValues>> {
-
-    @NonNull
-    private final Iterable<ContentValues> contentValues;
-
-    @NonNull
-    private final PutResolver<ContentValues> putResolver;
-
-    PreparedPutContentValuesIterable(@NonNull StorIOContentResolver storIOContentResolver,
-                                     @NonNull PutResolver<ContentValues> putResolver,
-                                     @NonNull Iterable<ContentValues> contentValues) {
-        super(storIOContentResolver);
-        this.contentValues = contentValues;
-        this.putResolver = putResolver;
-    }
-
-    /**
-     * Executes Put Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null results of Put Operation.
-     */
-    @WorkerThread
-    @NonNull
-    @Override
-    public PutResults<ContentValues> executeAsBlocking() {
-        final Map<ContentValues, PutResult> putResultsMap = new HashMap<ContentValues, PutResult>();
-
-        for (final ContentValues cv : contentValues) {
-            final PutResult putResult = putResolver.performPut(storIOContentResolver, cv);
-            putResultsMap.put(cv, putResult);
-        }
-
-        return PutResults.newInstance(putResultsMap);
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Put Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * put only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Put Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<PutResults<ContentValues>> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedPutContentValuesIterable}.
-     * <p/>
-     * Required: You should specify query see {@link #withPutResolver(PutResolver)}.
-     */
-    public static final class Builder {
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        @NonNull
-        private final Iterable<ContentValues> contentValues;
-
-        public Builder(@NonNull StorIOContentResolver storIOContentResolver,
-                       @NonNull Iterable<ContentValues> contentValues) {
-            this.storIOContentResolver = storIOContentResolver;
-            this.contentValues = contentValues;
-        }
-
-        /**
-         * Required: Specifies resolver for Put Operation
-         * that should define behavior of Put Operation: insert or update
-         * of the {@link ContentValues}.
-         *
-         * @param putResolver resolver for Put Operation.
-         * @return builder.
-         */
-        @NonNull
-        public CompleteBuilder withPutResolver(@NonNull PutResolver<ContentValues> putResolver) {
-            checkNotNull(putResolver, "Please specify PutResolver");
-            return new CompleteBuilder(storIOContentResolver, contentValues, putResolver);
-        }
-    }
-
-    /**
-     * Compile-time safe part of builder for {@link PreparedPutContentValuesIterable}.
-     */
-    public static final class CompleteBuilder {
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        @NonNull
-        private final Iterable<ContentValues> contentValues;
-
-        @NonNull
-        private final PutResolver<ContentValues> putResolver;
-
-        CompleteBuilder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Iterable<ContentValues> contentValues, @NonNull PutResolver<ContentValues> putResolver) {
-            this.storIOContentResolver = storIOContentResolver;
-            this.contentValues = contentValues;
-            this.putResolver = putResolver;
-        }
-
-        /**
-         * Builds instance of {@link PreparedPutContentValuesIterable}.
-         *
-         * @return instance of {@link PreparedPutContentValuesIterable}.
-         */
-        @NonNull
-        public PreparedPutContentValuesIterable prepare() {
-            return new PreparedPutContentValuesIterable(
-                    storIOContentResolver,
-                    putResolver,
-                    contentValues
-            );
-        }
-    }
-}
\ No newline at end of file
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutObject.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutObject.java
deleted file mode 100644
index 35a789e..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutObject.java
+++ /dev/null
@@ -1,148 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Put Operation to perform put object
- * into {@link StorIOContentResolver}.
- *
- * @param <T> type of the object.
- */
-public final class PreparedPutObject<T> extends PreparedPut<PutResult> {
-
-    @NonNull
-    private final T object;
-
-    @Nullable
-    private final PutResolver<T> explicitPutResolver;
-
-    PreparedPutObject(@NonNull StorIOContentResolver storIOContentResolver,
-                      @Nullable PutResolver<T> explicitPutResolver,
-                      @NonNull T object) {
-        super(storIOContentResolver);
-        this.object = object;
-        this.explicitPutResolver = explicitPutResolver;
-    }
-
-    /**
-     * Executes Put Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null results of Put Operation.
-     */
-    @SuppressWarnings("unchecked")
-    @WorkerThread
-    @NonNull
-    @Override
-    public PutResult executeAsBlocking() {
-        final PutResolver<T> putResolver;
-
-        if (explicitPutResolver != null) {
-            putResolver = explicitPutResolver;
-        } else {
-            final ContentResolverTypeMapping<T> typeMapping
-                    = storIOContentResolver.internal().typeMapping((Class<T>) object.getClass());
-
-            if (typeMapping == null) {
-                throw new IllegalStateException("Object does not have type mapping: " +
-                        "object = " + object + ", object.class = " + object.getClass() + "," +
-                        "ContentProvider was not affected by this operation, please add type mapping for this type");
-            }
-
-            putResolver = typeMapping.putResolver();
-        }
-
-        return putResolver.performPut(storIOContentResolver, object);
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Put Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * put only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Put Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<PutResult> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedPutObject}.
-     *
-     * @param <T> type of object.
-     */
-    public static final class Builder<T> {
-
-        @NonNull
-        private final StorIOContentResolver storIOContentResolver;
-
-        @NonNull
-        private final T object;
-
-        private PutResolver<T> putResolver;
-
-        public Builder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull T object) {
-            this.storIOContentResolver = storIOContentResolver;
-            this.object = object;
-        }
-
-        /**
-         * Optional: Specifies resolver for Put Operation
-         * that should define behavior of Put Operation: insert or update
-         * of the object.
-         * <p/>
-         * Can be set via {@link ContentResolverTypeMapping},
-         * If value is not set via {@link ContentResolverTypeMapping}
-         * or explicitly -> exception will be thrown.
-         *
-         * @param putResolver nullable resolver for Put Operation.
-         * @return builder.
-         */
-        @NonNull
-        public Builder<T> withPutResolver(@Nullable PutResolver<T> putResolver) {
-            this.putResolver = putResolver;
-            return this;
-        }
-
-        /**
-         * Builds instance of {@link PreparedPutObject}.
-         *
-         * @return instance of {@link PreparedPutObject}.
-         */
-        @NonNull
-        public PreparedPutObject<T> prepare() {
-            return new PreparedPutObject<T>(
-                    storIOContentResolver,
-                    putResolver,
-                    object
-            );
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PutResolver.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PutResolver.java
deleted file mode 100644
index 37beb5b..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PutResolver.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-
-/**
- * Defines behavior of Put Operation (insert or update).
- *
- * @param <T> type of objects to put.
- * @see DefaultPutResolver
- */
-public abstract class PutResolver<T> {
-
-    /**
-     * Performs Put Operation of some {@link android.content.ContentValues}
-     * into {@link StorIOContentResolver}.
-     *
-     * @param storIOContentResolver instance of {@link StorIOContentResolver}.
-     * @param object                non-null object of required type to put.
-     * @return non-null result of Put Operation.
-     */
-    @NonNull
-    public abstract PutResult performPut(@NonNull StorIOContentResolver storIOContentResolver, @NonNull T object);
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PutResult.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PutResult.java
deleted file mode 100644
index 25f17f6..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PutResult.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-/**
- * Immutable container for single result of Put Operation.
- */
-public final class PutResult {
-
-    @Nullable
-    private final Uri insertedUri;
-
-    @Nullable
-    private final Integer numberOfRowsUpdated;
-
-    @NonNull
-    private final Uri affectedUri;
-
-    private PutResult(@Nullable Uri insertedUri, @Nullable Integer numberOfRowsUpdated, @NonNull Uri affectedUri) {
-        this.insertedUri = insertedUri;
-        this.numberOfRowsUpdated = numberOfRowsUpdated;
-        this.affectedUri = affectedUri;
-    }
-
-    /**
-     * Creates {@link PutResult} for insert.
-     *
-     * @param insertedUri Uri of inserted row.
-     * @param affectedUri Uri that was affected by insert.
-     * @return new {@link PutResult} instance.
-     */
-    @NonNull
-    public static PutResult newInsertResult(@NonNull Uri insertedUri, @NonNull Uri affectedUri) {
-        return new PutResult(insertedUri, null, affectedUri);
-    }
-
-    /**
-     * Creates {@link PutResult} for update.
-     *
-     * @param numberOfRowsUpdated number of rows that were updated.
-     * @param affectedUri         Uri that was affected by update.
-     * @return new {@link PutResult} instance.
-     */
-    @NonNull
-    public static PutResult newUpdateResult(int numberOfRowsUpdated, @NonNull Uri affectedUri) {
-        return new PutResult(null, numberOfRowsUpdated, affectedUri);
-    }
-
-    /**
-     * Checks whether result of Put Operation was "insert".
-     *
-     * @return {@code true} if something was inserted into
-     * {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver},
-     * {@code false} otherwise.
-     */
-    public boolean wasInserted() {
-        return insertedUri != null;
-    }
-
-    /**
-     * Checks whether result of Put Operation was NOT "insert".
-     *
-     * @return {@code true} if nothing was inserted
-     * into {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver},
-     * {@code false} if something was inserted.
-     */
-    public boolean wasNotInserted() {
-        return !wasInserted();
-    }
-
-    /**
-     * Checks whether result of Put Operation was "update".
-     *
-     * @return {@code true} if something was updated in
-     * {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver},
-     * {@code false} otherwise.
-     */
-    public boolean wasUpdated() {
-        return numberOfRowsUpdated != null;
-    }
-
-    /**
-     * Checks whether result of Put Operation was NOT "update".
-     *
-     * @return {@code true} if nothing was updated
-     * in {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver},
-     * {@code false} if something was updated.
-     */
-    public boolean wasNotUpdated() {
-        return !wasUpdated();
-    }
-
-    /**
-     * Gets id of inserted row.
-     *
-     * @return null if nothing was inserted or id of inserted row.
-     */
-    @Nullable
-    public Uri insertedUri() {
-        return insertedUri;
-    }
-
-    /**
-     * Gets number of updated rows.
-     *
-     * @return null if nothing was updated or number of updated rows.
-     */
-    @Nullable
-    public Integer numberOfRowsUpdated() {
-        return numberOfRowsUpdated;
-    }
-
-    /**
-     * Gets Uri that was affected by this Put.
-     *
-     * @return non-null affected Uri.
-     */
-    @NonNull
-    public Uri affectedUri() {
-        return affectedUri;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        PutResult putResult = (PutResult) o;
-
-        if (insertedUri != null ? !insertedUri.equals(putResult.insertedUri) : putResult.insertedUri != null)
-            return false;
-        if (numberOfRowsUpdated != null ? !numberOfRowsUpdated.equals(putResult.numberOfRowsUpdated) : putResult.numberOfRowsUpdated != null)
-            return false;
-        return affectedUri.equals(putResult.affectedUri);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = insertedUri != null ? insertedUri.hashCode() : 0;
-        result = 31 * result + (numberOfRowsUpdated != null ? numberOfRowsUpdated.hashCode() : 0);
-        result = 31 * result + affectedUri.hashCode();
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "PutResult{" +
-                "insertedUri=" + insertedUri +
-                ", numberOfRowsUpdated=" + numberOfRowsUpdated +
-                ", affectedUri=" + affectedUri +
-                '}';
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PutResults.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PutResults.java
deleted file mode 100644
index 0221a87..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operation/put/PutResults.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * Immutable container for results of Put Operation of collection of objects.
- *
- * @param <T> type of objects.
- */
-public final class PutResults<T> {
-
-    @NonNull
-    private final Map<T, PutResult> results;
-
-    @Nullable
-    private volatile Integer numberOfInsertsCache;
-
-    @Nullable
-    private volatile Integer numberOfUpdatesCache;
-
-    private PutResults(@NonNull Map<T, PutResult> putResults) {
-        this.results = Collections.unmodifiableMap(putResults);
-    }
-
-    /**
-     * Creates new instance of {@link PutResults}.
-     *
-     * @param putResults results of Put Operation.
-     * @param <T>        type of objects.
-     * @return immutable instance of {@link PutResults}.
-     */
-    @NonNull
-    public static <T> PutResults<T> newInstance(@NonNull Map<T, PutResult> putResults) {
-        return new PutResults<T>(putResults);
-    }
-
-    /**
-     * Returns immutable Map of pairs {@code (object, PutResult)}.
-     *
-     * @return immutable Map of pairs {@code (object, PutResult)}.
-     */
-    @NonNull
-    public Map<T, PutResult> results() {
-        return results;
-    }
-
-    /**
-     * Returns number of inserts from all {@link #results()}.
-     *
-     * @return number of inserts from all {@link #results()}.
-     */
-    public int numberOfInserts() {
-        final Integer cachedValue = numberOfInsertsCache;
-
-        if (cachedValue != null) {
-            return cachedValue;
-        }
-
-        int numberOfInserts = 0;
-
-        for (T object : results.keySet()) {
-            if (results.get(object).wasInserted()) {
-                numberOfInserts++;
-            }
-        }
-
-        numberOfInsertsCache = numberOfInserts;
-
-        return numberOfInserts;
-    }
-
-    /**
-     * Returns number of updates from all {@link #results()}.
-     *
-     * @return number of updates from all {@link #results()}.
-     */
-    public int numberOfUpdates() {
-        final Integer cachedValue = numberOfUpdatesCache;
-
-        if (cachedValue != null) {
-            return cachedValue;
-        }
-
-        int numberOfUpdates = 0;
-
-        for (T object : results.keySet()) {
-            final PutResult putResult = results.get(object);
-
-            if (putResult.wasUpdated()) {
-                //noinspection ConstantConditions
-                numberOfUpdates += putResult.numberOfRowsUpdated();
-            }
-        }
-
-        numberOfUpdatesCache = numberOfUpdates;
-
-        return numberOfUpdates;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        PutResults<?> that = (PutResults<?>) o;
-
-        return results.equals(that.results);
-    }
-
-    @Override
-    public int hashCode() {
-        return results.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        return "PutResults{" +
-                "results=" + results +
-                '}';
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DefaultDeleteResolver.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DefaultDeleteResolver.java
new file mode 100644
index 0000000..c485b38
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DefaultDeleteResolver.java
@@ -0,0 +1,36 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+
+/**
+ * Default implementation of {@link DeleteResolver}.
+ * <p/>
+ * Simply redirects {@link DeleteQuery} to {@link StorIOContentResolver}.
+ * <p/>
+ * Instances of this class are thread-safe.
+ */
+public abstract class DefaultDeleteResolver<T> extends DeleteResolver<T> {
+
+    /**
+     * Converts object of required type to {@link DeleteQuery}.
+     *
+     * @param object non-null object that should be converted to {@link DeleteQuery}.
+     * @return non-null {@link DeleteQuery}.
+     */
+    @NonNull
+    protected abstract DeleteQuery mapToDeleteQuery(@NonNull T object);
+
+    /**
+     * {@inheritDoc}
+     */
+    @NonNull
+    @Override
+    public DeleteResult performDelete(@NonNull StorIOContentResolver storIOContentResolver, @NonNull T object) {
+        final DeleteQuery deleteQuery = mapToDeleteQuery(object);
+        final int numberOfRowsDeleted = storIOContentResolver.internal().delete(deleteQuery);
+        return DeleteResult.newInstance(numberOfRowsDeleted, deleteQuery.uri());
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResolver.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResolver.java
new file mode 100644
index 0000000..d614c0e
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResolver.java
@@ -0,0 +1,21 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+
+/**
+ * Defines behavior Delete Operation behavior.
+ */
+public abstract class DeleteResolver<T> {
+
+    /**
+     * Performs Delete Operation.
+     *
+     * @param storIOContentResolver instance of {@link StorIOContentResolver}.
+     * @param object                non-null object that should be deleted.
+     * @return non-null result of Delete Operation.
+     */
+    @NonNull
+    public abstract DeleteResult performDelete(@NonNull StorIOContentResolver storIOContentResolver, @NonNull T object);
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResult.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResult.java
new file mode 100644
index 0000000..bfc67e1
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResult.java
@@ -0,0 +1,98 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import java.util.Collections;
+import java.util.Set;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+
+/**
+ * Immutable container for results of Delete Operation.
+ * <p/>
+ * Instances of this class are Immutable.
+ */
+public final class DeleteResult {
+
+    private final int numberOfRowsDeleted;
+
+    @NonNull
+    private final Set<Uri> affectedUris;
+
+    private DeleteResult(int numberOfRowsDeleted, @NonNull Set<Uri> affectedUris) {
+        this.numberOfRowsDeleted = numberOfRowsDeleted;
+        this.affectedUris = Collections.unmodifiableSet(affectedUris);
+    }
+
+    /**
+     * Creates new instance of immutable container for results of Delete Operation.
+     *
+     * @param numberOfRowsDeleted number of rows that were deleted.
+     * @param affectedUris        non-null set of Uris that wer affected.
+     * @return new instance of immutable container for results of Delete Operation.
+     */
+    @NonNull
+    public static DeleteResult newInstance(int numberOfRowsDeleted, @NonNull Set<Uri> affectedUris) {
+        checkNotNull(affectedUris, "Please specify affected Uris");
+        return new DeleteResult(numberOfRowsDeleted, affectedUris);
+    }
+
+    /**
+     * Creates new instance of immutable container for results of Delete Operation.
+     *
+     * @param numberOfRowsDeleted number of rows that were deleted.
+     * @param affectedUri         non-null Uri that was affected.
+     * @return new instance of immutable container for results of Delete Operation.
+     */
+    @NonNull
+    public static DeleteResult newInstance(int numberOfRowsDeleted, @NonNull Uri affectedUri) {
+        checkNotNull(affectedUri, "Please specify affected Uri");
+        return new DeleteResult(numberOfRowsDeleted, Collections.singleton(affectedUri));
+    }
+
+    /**
+     * Gets number of rows that were deleted.
+     *
+     * @return number of rows that were deleted.
+     */
+    public int numberOfRowsDeleted() {
+        return numberOfRowsDeleted;
+    }
+
+    /**
+     * Gets immutable set of affected Uris.
+     *
+     * @return affected Uris.
+     */
+    @NonNull
+    public Set<Uri> affectedUris() {
+        return affectedUris;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        DeleteResult that = (DeleteResult) o;
+
+        if (numberOfRowsDeleted != that.numberOfRowsDeleted) return false;
+        return affectedUris.equals(that.affectedUris);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = numberOfRowsDeleted;
+        result = 31 * result + affectedUris.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "DeleteResult{" +
+                "numberOfRowsDeleted=" + numberOfRowsDeleted +
+                ", affectedUris=" + affectedUris +
+                '}';
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResults.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResults.java
new file mode 100644
index 0000000..a433747
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResults.java
@@ -0,0 +1,81 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import android.support.annotation.NonNull;
+
+import java.util.Collections;
+import java.util.Map;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+
+/**
+ * Immutable container for multiple results of Delete Operation.
+ * <p/>
+ * Instances of this class are immutable.
+ */
+public final class DeleteResults<T> {
+
+    @NonNull
+    private final Map<T, DeleteResult> results;
+
+    private DeleteResults(@NonNull Map<T, DeleteResult> results) {
+        this.results = Collections.unmodifiableMap(results);
+    }
+
+    @NonNull
+    public static <T> DeleteResults<T> newInstance(@NonNull Map<T, DeleteResult> results) {
+        checkNotNull(results, "Please specify delete results map");
+        return new DeleteResults<T>(results);
+    }
+
+    /**
+     * Gets immutable Map of pairs (object, DeleteResult).
+     *
+     * @return immutable Map of pairs (object, DeleteResult).
+     */
+    @NonNull
+    public Map<T, DeleteResult> results() {
+        return results;
+    }
+
+    /**
+     * Checks whether particular object was deleted.
+     *
+     * @param object object to check.
+     * @return true if object was deleted, false otherwise.
+     */
+    public boolean wasDeleted(@NonNull T object) {
+        return results.containsKey(object);
+    }
+
+    /**
+     * Checks whether particular object was NOT deleted.
+     *
+     * @param object object to check.
+     * @return true if object was NOT deleter, false if it was deleted.
+     */
+    public boolean wasNotDeleted(@NonNull T object) {
+        return !results.containsKey(object);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        DeleteResults<?> that = (DeleteResults<?>) o;
+
+        return results.equals(that.results);
+    }
+
+    @Override
+    public int hashCode() {
+        return results.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "DeleteResults{" +
+                "results=" + results +
+                '}';
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDelete.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDelete.java
new file mode 100644
index 0000000..38bb3fe
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDelete.java
@@ -0,0 +1,80 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+import com.pushtorefresh.storio.operations.PreparedOperation;
+
+import java.util.Collection;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+
+/**
+ * Prepared Delete Operation for {@link StorIOContentResolver}.
+ *
+ * @param <Result> type of result of Delete Operation.
+ */
+public abstract class PreparedDelete<Result> implements PreparedOperation<Result> {
+
+    @NonNull
+    protected final StorIOContentResolver storIOContentResolver;
+
+    PreparedDelete(@NonNull StorIOContentResolver storIOContentResolver) {
+        this.storIOContentResolver = storIOContentResolver;
+    }
+
+    /**
+     * Builder for {@link PreparedDelete}.
+     */
+    public static final class Builder {
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        /**
+         * Creates new builder for {@link PreparedDelete}.
+         *
+         * @param storIOContentResolver non-null instance of {@link StorIOContentResolver}.
+         */
+        public Builder(@NonNull StorIOContentResolver storIOContentResolver) {
+            checkNotNull(storIOContentResolver, "Please specify StorIOContentResolver");
+            this.storIOContentResolver = storIOContentResolver;
+        }
+
+        /**
+         * Creates builder for {@link PreparedDeleteByQuery}.
+         *
+         * @param deleteQuery non-null delete query.
+         * @return builder for {@link PreparedDeleteByQuery}.
+         */
+        @NonNull
+        public PreparedDeleteByQuery.Builder byQuery(@NonNull DeleteQuery deleteQuery) {
+            return new PreparedDeleteByQuery.Builder(storIOContentResolver, deleteQuery);
+        }
+
+        /**
+         * Creates builder for {@link PreparedDeleteCollectionOfObjects}.
+         *
+         * @param objects non-null collection of objects to delete.
+         * @param <T>     type of objects.
+         * @return builder for {@link PreparedDeleteCollectionOfObjects}.
+         */
+        @NonNull
+        public <T> PreparedDeleteCollectionOfObjects.Builder<T> objects(@NonNull Collection<T> objects) {
+            return new PreparedDeleteCollectionOfObjects.Builder<T>(storIOContentResolver, objects);
+        }
+
+        /**
+         * Creates builder for {@link PreparedDeleteObject}.
+         *
+         * @param object non-null object to delete.
+         * @param <T>    type of object.
+         * @return builder for {@link PreparedDeleteObject}.
+         */
+        @NonNull
+        public <T> PreparedDeleteObject.Builder<T> object(@NonNull T object) {
+            return new PreparedDeleteObject.Builder<T>(storIOContentResolver, object);
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteByQuery.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteByQuery.java
new file mode 100644
index 0000000..a3c5e05
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteByQuery.java
@@ -0,0 +1,146 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Delete Operation for
+ * {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver}.
+ */
+public final class PreparedDeleteByQuery extends PreparedDelete<DeleteResult> {
+
+    @NonNull
+    private final DeleteQuery deleteQuery;
+
+    @NonNull
+    private final DeleteResolver<DeleteQuery> deleteResolver;
+
+    PreparedDeleteByQuery(@NonNull StorIOContentResolver storIOContentResolver,
+                          @NonNull DeleteQuery deleteQuery,
+                          @NonNull DeleteResolver<DeleteQuery> deleteResolver) {
+        super(storIOContentResolver);
+        this.deleteQuery = deleteQuery;
+        this.deleteResolver = deleteResolver;
+    }
+
+    /**
+     * Executes Delete Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null result of Delete Operation.
+     */
+    @WorkerThread
+    @NonNull
+    @Override
+    public DeleteResult executeAsBlocking() {
+        return deleteResolver.performDelete(storIOContentResolver, deleteQuery);
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Delete Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * delete only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Delete Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<DeleteResult> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedDeleteByQuery}.
+     */
+    public static final class Builder {
+
+        private static final DeleteResolver<DeleteQuery> STANDARD_DELETE_RESOLVER = new DefaultDeleteResolver<DeleteQuery>() {
+            @NonNull
+            @Override
+            protected DeleteQuery mapToDeleteQuery(@NonNull DeleteQuery deleteQuery) {
+                return deleteQuery; // easy
+            }
+        };
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        @NonNull
+        private final DeleteQuery deleteQuery;
+
+        private DeleteResolver<DeleteQuery> deleteResolver;
+
+        /**
+         * Creates builder for {@link PreparedDeleteByQuery}.
+         *
+         * @param storIOContentResolver non-null instance of {@link StorIOContentResolver}.
+         * @param deleteQuery           non-null instance of {@link DeleteQuery}.
+         */
+        public Builder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull DeleteQuery deleteQuery) {
+            checkNotNull(storIOContentResolver, "Please specify StorIOContentResolver");
+            checkNotNull(deleteQuery, "Please specify delete query");
+
+            this.storIOContentResolver = storIOContentResolver;
+            this.deleteQuery = deleteQuery;
+        }
+
+        /**
+         * Optional: Specifies resolver for Delete Operation.
+         * Allows you to customise behavior of Delete Operation.
+         * <p/>
+         * If no value will be set, builder will use Delete Resolver
+         * that simply redirects query to {@link StorIOContentResolver}.
+         *
+         * @param deleteResolver nullable resolver for Delete Operation.
+         * @return builder.
+         */
+        @NonNull
+        public Builder withDeleteResolver(@Nullable DeleteResolver<DeleteQuery> deleteResolver) {
+            this.deleteResolver = deleteResolver;
+            return this;
+        }
+
+        /**
+         * Builds instance of {@link PreparedDeleteByQuery}.
+         *
+         * @return instance of {@link PreparedDeleteByQuery}.
+         */
+        @NonNull
+        public PreparedDeleteByQuery prepare() {
+            if (deleteResolver == null) {
+                deleteResolver = STANDARD_DELETE_RESOLVER;
+            }
+
+            return new PreparedDeleteByQuery(
+                    storIOContentResolver,
+                    deleteQuery,
+                    deleteResolver
+            );
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteCollectionOfObjects.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteCollectionOfObjects.java
new file mode 100644
index 0000000..8f825fa
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteCollectionOfObjects.java
@@ -0,0 +1,187 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Delete Operation for {@link StorIOContentResolver}.
+ *
+ * @param <T> type of objects to delete.
+ */
+public final class PreparedDeleteCollectionOfObjects<T> extends PreparedDelete<DeleteResults<T>> {
+
+    @NonNull
+    private final Collection<T> objects;
+
+    @Nullable
+    private final DeleteResolver<T> explicitDeleteResolver;
+
+    PreparedDeleteCollectionOfObjects(@NonNull StorIOContentResolver storIOContentResolver,
+                                      @NonNull Collection<T> objects,
+                                      @Nullable DeleteResolver<T> explicitDeleteResolver) {
+        super(storIOContentResolver);
+        this.objects = objects;
+        this.explicitDeleteResolver = explicitDeleteResolver;
+    }
+
+    /**
+     * Executes Delete Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null results of Delete Operation.
+     */
+    @SuppressWarnings("unchecked")
+    @WorkerThread
+    @NonNull
+    @Override
+    public DeleteResults<T> executeAsBlocking() {
+        final StorIOContentResolver.Internal internal = storIOContentResolver.internal();
+
+        // Nullable
+        final List<SimpleImmutableEntry> objectsAndDeleteResolvers;
+
+        if (explicitDeleteResolver != null) {
+            objectsAndDeleteResolvers = null;
+        } else {
+            objectsAndDeleteResolvers = new ArrayList<SimpleImmutableEntry>(objects.size());
+
+            for (final T object : objects) {
+                final ContentResolverTypeMapping<T> typeMapping
+                        = (ContentResolverTypeMapping<T>) internal.typeMapping(object.getClass());
+
+                if (typeMapping == null) {
+                    throw new IllegalStateException("One of the objects from the collection does not have type mapping: " +
+                            "object = " + object + ", object.class = " + object.getClass() + "," +
+                            "ContentProvider was not affected by this operation, please add type mapping for this type");
+                }
+
+                objectsAndDeleteResolvers.add(new SimpleImmutableEntry(
+                        object,
+                        typeMapping.deleteResolver()
+                ));
+            }
+        }
+
+        final Map<T, DeleteResult> results = new HashMap<T, DeleteResult>(objects.size());
+
+        if (explicitDeleteResolver != null) {
+            for (final T object : objects) {
+                final DeleteResult deleteResult = explicitDeleteResolver.performDelete(storIOContentResolver, object);
+                results.put(object, deleteResult);
+            }
+        } else {
+            for (final SimpleImmutableEntry<T, DeleteResolver<T>> objectAndDeleteResolver : objectsAndDeleteResolvers) {
+                final T object = objectAndDeleteResolver.getKey();
+                final DeleteResolver<T> deleteResolver = objectAndDeleteResolver.getValue();
+
+                final DeleteResult deleteResult = deleteResolver.performDelete(storIOContentResolver, object);
+                results.put(object, deleteResult);
+            }
+        }
+
+        return DeleteResults.newInstance(results);
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Delete Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * delete only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Delete Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<DeleteResults<T>> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedDeleteCollectionOfObjects}.
+     *
+     * @param <T> type of objects.
+     */
+    public static final class Builder<T> {
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        @NonNull
+        private final Collection<T> objects;
+
+        @Nullable
+        private DeleteResolver<T> deleteResolver;
+
+        /**
+         * Creates builder for {@link PreparedDeleteCollectionOfObjects}.
+         *
+         * @param storIOContentResolver non-null instance of {@link StorIOContentResolver}.
+         * @param objects               non-null collection of objects to delete.
+         */
+        public Builder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Collection<T> objects) {
+            this.storIOContentResolver = storIOContentResolver;
+            this.objects = objects;
+        }
+
+        /**
+         * Optional: Specifies resolver for Delete Operation.
+         * Allows you to customise behavior of Delete Operation.
+         * <p/>
+         * Can be set via {@link ContentResolverTypeMapping},
+         * If value is not set via {@link ContentResolverTypeMapping}
+         * or explicitly -> exception will be thrown.
+         *
+         * @param deleteResolver nullable resolver for Delete Operation.
+         * @return builder.
+         */
+        @NonNull
+        public Builder<T> withDeleteResolver(@Nullable DeleteResolver<T> deleteResolver) {
+            this.deleteResolver = deleteResolver;
+            return this;
+        }
+
+        /**
+         * Builds instance of {@link PreparedDeleteCollectionOfObjects}.
+         *
+         * @return instance of {@link PreparedDeleteCollectionOfObjects}.
+         */
+        @NonNull
+        public PreparedDeleteCollectionOfObjects<T> prepare() {
+            return new PreparedDeleteCollectionOfObjects<T>(
+                    storIOContentResolver,
+                    objects,
+                    deleteResolver
+            );
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteObject.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteObject.java
new file mode 100644
index 0000000..6402a6f
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteObject.java
@@ -0,0 +1,155 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Delete Operation for
+ * {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver}.
+ */
+public final class PreparedDeleteObject<T> extends PreparedDelete<DeleteResult> {
+
+    @NonNull
+    private final T object;
+
+    @Nullable
+    private final DeleteResolver<T> explicitDeleteResolver;
+
+    PreparedDeleteObject(@NonNull StorIOContentResolver storIOContentResolver,
+                         @NonNull T object,
+                         @Nullable DeleteResolver<T> explicitDeleteResolver) {
+        super(storIOContentResolver);
+        this.object = object;
+        this.explicitDeleteResolver = explicitDeleteResolver;
+    }
+
+    /**
+     * Executes Delete Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null result of Delete Operation.
+     */
+    @SuppressWarnings("unchecked")
+    @WorkerThread
+    @NonNull
+    @Override
+    public DeleteResult executeAsBlocking() {
+        final DeleteResolver<T> deleteResolver;
+
+        if (explicitDeleteResolver != null) {
+            deleteResolver = explicitDeleteResolver;
+        } else {
+            final ContentResolverTypeMapping<T> typeMapping
+                    = storIOContentResolver.internal().typeMapping((Class<T>) object.getClass());
+
+            if (typeMapping == null) {
+                throw new IllegalStateException("Object does not have type mapping: " +
+                        "object = " + object + ", object.class = " + object.getClass() + "," +
+                        "ContentProvider was not affected by this operation, please add type mapping for this type");
+            }
+
+            deleteResolver = typeMapping.deleteResolver();
+        }
+
+        return deleteResolver.performDelete(storIOContentResolver, object);
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Delete Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * delete only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Delete Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<DeleteResult> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedDeleteObject}.
+     *
+     * @param <T> type of object to delete.
+     */
+    public static final class Builder<T> {
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        @NonNull
+        private final T object;
+
+        private DeleteResolver<T> deleteResolver;
+
+        /**
+         * Creates builder for {@link PreparedDeleteObject}.
+         *
+         * @param storIOContentResolver non-null instance of {@link StorIOContentResolver}.
+         * @param object                non-null object that should be deleted.
+         */
+        public Builder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull T object) {
+            checkNotNull(storIOContentResolver, "Please specify StorIOContentResolver");
+            checkNotNull(object, "Please specify object to delete");
+
+            this.storIOContentResolver = storIOContentResolver;
+            this.object = object;
+        }
+
+        /**
+         * Optional: Specifies resolver for Delete Operation.
+         * Allows you to customise behavior of Delete Operation.
+         * <p/>
+         * Can be set via {@link ContentResolverTypeMapping},
+         * If value is not set via {@link ContentResolverTypeMapping}
+         * or explicitly -> exception will be thrown.
+         *
+         * @param deleteResolver resolver for Delete Operation.
+         * @return builder.
+         */
+        @NonNull
+        public Builder<T> withDeleteResolver(@NonNull DeleteResolver<T> deleteResolver) {
+            this.deleteResolver = deleteResolver;
+            return this;
+        }
+
+        /**
+         * Builds new instance of {@link PreparedDeleteObject}.
+         *
+         * @return new instance of {@link PreparedDeleteObject}.
+         */
+        @NonNull
+        public PreparedDeleteObject<T> prepare() {
+            return new PreparedDeleteObject<T>(
+                    storIOContentResolver,
+                    object,
+                    deleteResolver
+            );
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/DefaultGetResolver.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/DefaultGetResolver.java
new file mode 100644
index 0000000..3c705d3
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/DefaultGetResolver.java
@@ -0,0 +1,22 @@
+package com.pushtorefresh.storio.contentresolver.operations.get;
+
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
+
+/**
+ * Default implementation of {@link GetResolver}, thread-safe.
+ */
+public abstract class DefaultGetResolver<T> extends GetResolver<T> {
+
+    /**
+     * {@inheritDoc}
+     */
+    @NonNull
+    @Override
+    public Cursor performGet(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Query query) {
+        return storIOContentResolver.internal().query(query);
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/GetResolver.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/GetResolver.java
new file mode 100644
index 0000000..3c533c7
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/GetResolver.java
@@ -0,0 +1,40 @@
+package com.pushtorefresh.storio.contentresolver.operations.get;
+
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
+
+/**
+ * Defines behavior of Get Operation.
+ */
+public abstract class GetResolver<T> {
+
+    /**
+     * Converts {@link Cursor} with already set position to object of required type.
+     *
+     * @param cursor not closed {@link Cursor} with already set position
+     *               that should be parsed and converted to object of required type.
+     * @return non-null object of required type with data parsed from passed {@link Cursor}.
+     */
+    @NonNull
+    public abstract T mapFromCursor(@NonNull Cursor cursor);
+
+    /**
+     * Performs Get Operation
+     *
+     * @param storIOContentResolver non-null instance of {@link StorIOContentResolver}.
+     * @param query                 non-null query that should be processed.
+     * @return non-null, not closed {@link Cursor} that can be empty or contain
+     * data with results of Get Operation.
+     * <p>
+     * Notice, that {@link android.content.ContentProvider} can return null {@link Cursor}
+     * from {@link android.content.ContentProvider#query(android.net.Uri, String[], String, String[], String)}
+     * But null {@link Cursor} is not very great thing to work with,
+     * so if {@link android.content.ContentProvider} returns null,
+     * {@link StorIOContentResolver} will return empty cursor.
+     */
+    @NonNull
+    public abstract Cursor performGet(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Query query);
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGet.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGet.java
new file mode 100644
index 0000000..b12aa92
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGet.java
@@ -0,0 +1,56 @@
+package com.pushtorefresh.storio.contentresolver.operations.get;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.operations.PreparedOperation;
+
+/**
+ * Represents Get Operation for {@link StorIOContentResolver}.
+ *
+ * @param <Result> type of result.
+ */
+public abstract class PreparedGet<Result> implements PreparedOperation<Result> {
+
+    @NonNull
+    protected final StorIOContentResolver storIOContentResolver;
+
+    PreparedGet(@NonNull StorIOContentResolver storIOContentResolver) {
+        this.storIOContentResolver = storIOContentResolver;
+    }
+
+    /**
+     * Builder for {@link PreparedGet}.
+     */
+    public final static class Builder {
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        public Builder(@NonNull StorIOContentResolver storIOContentResolver) {
+            this.storIOContentResolver = storIOContentResolver;
+        }
+
+        /**
+         * Returns builder for Get Operation that returns result as {@link android.database.Cursor}.
+         *
+         * @return builder for Get Operation that returns result as {@link android.database.Cursor}.
+         */
+        @NonNull
+        public PreparedGetCursor.Builder cursor() {
+            return new PreparedGetCursor.Builder(storIOContentResolver);
+        }
+
+        /**
+         * Returns builder for Get Operation that returns result as {@link java.util.List} of items.
+         *
+         * @param type type of items.
+         * @param <T>  type of items.
+         * @return builder for Get Operation that returns result as {@link java.util.List} of items.
+         */
+        @NonNull
+        public <T> PreparedGetListOfObjects.Builder<T> listOfObjects(@NonNull Class<T> type) {
+            return new PreparedGetListOfObjects.Builder<T>(storIOContentResolver, type);
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetCursor.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetCursor.java
new file mode 100644
index 0000000..4b9c865
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetCursor.java
@@ -0,0 +1,172 @@
+package com.pushtorefresh.storio.contentresolver.operations.get;
+
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
+import com.pushtorefresh.storio.operations.internal.MapSomethingToExecuteAsBlocking;
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Represents Get Operation for {@link StorIOContentResolver}
+ * which performs query that retrieves data as {@link Cursor}.
+ * from {@link android.content.ContentProvider}.
+ */
+public final class PreparedGetCursor extends PreparedGet<Cursor> {
+
+    @NonNull
+    private final Query query;
+
+    @NonNull
+    private final GetResolver<Cursor> getResolver;
+
+    PreparedGetCursor(@NonNull StorIOContentResolver storIOContentResolver,
+                      @NonNull GetResolver<Cursor> getResolver,
+                      @NonNull Query query) {
+        super(storIOContentResolver);
+        this.query = query;
+        this.getResolver = getResolver;
+    }
+
+    /**
+     * Executes Get Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null {@link Cursor}, can be empty.
+     */
+    @WorkerThread
+    @NonNull
+    @Override
+    public Cursor executeAsBlocking() {
+        return getResolver.performGet(storIOContentResolver, query);
+    }
+
+    /**
+     * Creates "Hot" {@link Observable} which will be subscribed to changes of {@link #query} Uri
+     * and will emit result each time change occurs.
+     * <p/>
+     * First result will be emitted immediately after subscription,
+     * other emissions will occur only if changes of {@link #query} Uri will occur.
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     * <p/>
+     * Please don't forget to unsubscribe from this {@link Observable} because
+     * it's "Hot" and endless.
+     *
+     * @return non-null {@link Observable} which will emit non-null
+     * list with mapped results and will be subscribed to changes of {@link #query} Uri.
+     */
+    @NonNull
+    @Override
+    public Observable<Cursor> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return storIOContentResolver
+                .observeChangesOfUri(query.uri()) // each change triggers executeAsBlocking
+                .map(MapSomethingToExecuteAsBlocking.newInstance(this))
+                .startWith(Observable.create(OnSubscribeExecuteAsBlocking.newInstance(this))) // start stream with first query result
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedGetCursor}.
+     * <p/>
+     * Required: You should specify query see {@link #withQuery(Query)}.
+     */
+    public static final class Builder {
+
+        @NonNull
+        final StorIOContentResolver storIOContentResolver;
+
+        public Builder(@NonNull StorIOContentResolver storIOContentResolver) {
+            this.storIOContentResolver = storIOContentResolver;
+        }
+
+        /**
+         * Required: Specifies {@link Query} for Get Operation.
+         *
+         * @param query query.
+         * @return builder.
+         */
+        @NonNull
+        public CompleteBuilder withQuery(@NonNull Query query) {
+            checkNotNull(query, "Please specify Query");
+            return new CompleteBuilder(storIOContentResolver, query);
+        }
+    }
+
+    /**
+     * Compile-time safe part of builder for {@link PreparedGetCursor}.
+     */
+    public static final class CompleteBuilder {
+
+        private static final GetResolver<Cursor> STANDARD_GET_RESOLVER = new DefaultGetResolver<Cursor>() {
+            @NonNull
+            @Override
+            public Cursor mapFromCursor(@NonNull Cursor cursor) {
+                return cursor; // easy
+            }
+        };
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        @NonNull
+        private final Query query;
+
+        private GetResolver<Cursor> getResolver;
+
+        CompleteBuilder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Query query) {
+            this.storIOContentResolver = storIOContentResolver;
+            this.query = query;
+        }
+
+        /**
+         * Optional: Specifies {@link GetResolver} for Get Operation
+         * which allows you to customize behavior of Get Operation.
+         * <p/>
+         * If no value will be set, builder will use resolver that
+         * simply redirects query to {@link StorIOContentResolver}.
+         *
+         * @param getResolver GetResolver.
+         * @return builder.
+         */
+        @NonNull
+        public CompleteBuilder withGetResolver(@Nullable GetResolver<Cursor> getResolver) {
+            this.getResolver = getResolver;
+            return this;
+        }
+
+        /**
+         * Prepares Get Operation.
+         *
+         * @return {@link PreparedGetCursor} instance.
+         */
+        @NonNull
+        public PreparedGetCursor prepare() {
+            if (getResolver == null) {
+                getResolver = STANDARD_GET_RESOLVER;
+            }
+
+            return new PreparedGetCursor(
+                    storIOContentResolver,
+                    getResolver,
+                    query
+            );
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetListOfObjects.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetListOfObjects.java
new file mode 100644
index 0000000..86e89cb
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetListOfObjects.java
@@ -0,0 +1,221 @@
+package com.pushtorefresh.storio.contentresolver.operations.get;
+
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
+import com.pushtorefresh.storio.operations.internal.MapSomethingToExecuteAsBlocking;
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+import static java.util.Collections.EMPTY_LIST;
+import static java.util.Collections.unmodifiableList;
+
+/**
+ * Represents Get Operation for {@link StorIOContentResolver}
+ * which performs query that retrieves data as list of objects
+ * from {@link android.content.ContentProvider}.
+ *
+ * @param <T> type of result.
+ */
+public final class PreparedGetListOfObjects<T> extends PreparedGet<List<T>> {
+
+    @NonNull
+    private final Class<T> type;
+
+    @NonNull
+    private final Query query;
+
+    @Nullable
+    private final GetResolver<T> explicitGetResolver;
+
+    PreparedGetListOfObjects(@NonNull StorIOContentResolver storIOContentResolver,
+                             @NonNull Class<T> type,
+                             @NonNull Query query,
+                             @Nullable GetResolver<T> explicitGetResolver) {
+        super(storIOContentResolver);
+        this.type = type;
+        this.query = query;
+        this.explicitGetResolver = explicitGetResolver;
+    }
+
+    /**
+     * Executes Prepared Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null, immutable {@link List} with mapped results, list can be empty.
+     */
+    @WorkerThread
+    @SuppressWarnings("unchecked") // for empty list
+    @NonNull
+    @Override
+    public List<T> executeAsBlocking() {
+        final GetResolver<T> getResolver;
+
+        if (explicitGetResolver != null) {
+            getResolver = explicitGetResolver;
+        } else {
+            final ContentResolverTypeMapping<T> typeMapping = storIOContentResolver.internal().typeMapping(type);
+
+            if (typeMapping == null) {
+                throw new IllegalStateException("This type does not have type mapping: " +
+                        "type = " + type + "," +
+                        "ContentProvider was not touched by this operation, please add type mapping for this type");
+            }
+
+            getResolver = typeMapping.getResolver();
+        }
+
+        final Cursor cursor = getResolver.performGet(storIOContentResolver, query);
+
+        try {
+            final int count = cursor.getCount();
+
+            if (count == 0) {
+                return EMPTY_LIST; // it's immutable
+            } else {
+                final List<T> list = new ArrayList<T>(count);
+
+                while (cursor.moveToNext()) {
+                    list.add(getResolver.mapFromCursor(cursor));
+                }
+
+                return unmodifiableList(list);
+            }
+        } finally {
+            cursor.close();
+        }
+    }
+
+    /**
+     * Creates "Hot" {@link Observable} which will be subscribed to changes of {@link #query} Uri
+     * and will emit result each time change occurs.
+     * <p/>
+     * First result will be emitted immediately after subscription,
+     * other emissions will occur only if changes of {@link #query} Uri will occur.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     * <p/>
+     * Please don't forget to unsubscribe from this {@link Observable}
+     * because it's "Hot" and endless.
+     *
+     * @return non-null {@link Observable} which will emit non-null, immutable
+     * {@link List} with mapped results and will be subscribed to changes of {@link #query} Uri,
+     * list can be empty.
+     */
+    @NonNull
+    @Override
+    public Observable<List<T>> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return storIOContentResolver
+                .observeChangesOfUri(query.uri()) // each change triggers executeAsBlocking
+                .map(MapSomethingToExecuteAsBlocking.newInstance(this))
+                .startWith(Observable.create(OnSubscribeExecuteAsBlocking.newInstance(this))) // start stream with first query result
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Compile-time safe part of builder for {@link PreparedGetListOfObjects}.
+     *
+     * @param <T> type of objects for query.
+     */
+    public static final class Builder<T> {
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        @NonNull
+        private final Class<T> type;
+
+        public Builder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Class<T> type) {
+            this.storIOContentResolver = storIOContentResolver;
+            this.type = type;
+        }
+
+        /**
+         * Required: Specifies {@link Query} for Get Operation.
+         *
+         * @param query query.
+         * @return builder.
+         */
+        @NonNull
+        public CompleteBuilder<T> withQuery(@NonNull Query query) {
+            checkNotNull(query, "Please specify query");
+            return new CompleteBuilder<T>(storIOContentResolver, type, query);
+        }
+    }
+
+    /**
+     * Compile-time safe part of builder for {@link PreparedGetListOfObjects}.
+     *
+     * @param <T> type of objects for query.
+     */
+    public static final class CompleteBuilder<T> {
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        @NonNull
+        private final Class<T> type;
+
+        @NonNull
+        private final Query query;
+
+        private GetResolver<T> getResolver;
+
+        CompleteBuilder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Class<T> type, @NonNull Query query) {
+            this.storIOContentResolver = storIOContentResolver;
+            this.type = type;
+            this.query = query;
+        }
+
+        /**
+         * Optional: Specifies {@link GetResolver} for Get Operation
+         * which allows you to customize behavior of Get Operation.
+         * <p/>
+         * Can be set via {@link ContentResolverTypeMapping},
+         * If value is not set via {@link ContentResolverTypeMapping} -> exception will be thrown.
+         *
+         * @param getResolver GetResolver.
+         * @return builder.
+         */
+        @NonNull
+        public CompleteBuilder<T> withGetResolver(@Nullable GetResolver<T> getResolver) {
+            this.getResolver = getResolver;
+            return this;
+        }
+
+        /**
+         * Builds new instance of {@link PreparedGetListOfObjects}.
+         *
+         * @return new instance of {@link PreparedGetListOfObjects}.
+         */
+        @NonNull
+        public PreparedGetListOfObjects<T> prepare() {
+            return new PreparedGetListOfObjects<T>(
+                    storIOContentResolver,
+                    type,
+                    query,
+                    getResolver
+            );
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/DefaultPutResolver.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/DefaultPutResolver.java
new file mode 100644
index 0000000..149a6c4
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/DefaultPutResolver.java
@@ -0,0 +1,83 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
+import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;
+
+import static com.pushtorefresh.storio.internal.Queries.nullableArrayOfStrings;
+import static com.pushtorefresh.storio.internal.Queries.nullableString;
+
+/**
+ * Default thread-safe implementation of {@link PutResolver}.
+ *
+ * @param <T> type of objects to put.
+ */
+public abstract class DefaultPutResolver<T> extends PutResolver<T> {
+
+    /**
+     * Converts object of required type to {@link InsertQuery}.
+     *
+     * @param object non-null object that should be converted to {@link InsertQuery}.
+     * @return non-null {@link InsertQuery}.
+     */
+    @NonNull
+    protected abstract InsertQuery mapToInsertQuery(@NonNull T object);
+
+    /**
+     * Converts object of required type to {@link UpdateQuery}.
+     *
+     * @param object non-null object that should be converted to {@link UpdateQuery}.
+     * @return non-null {@link UpdateQuery}.
+     */
+    @NonNull
+    protected abstract UpdateQuery mapToUpdateQuery(@NonNull T object);
+
+    /**
+     * Converts object of required type to {@link ContentValues}.
+     *
+     * @param object non-null object that should be converted to {@link ContentValues}.
+     * @return non-null {@link ContentValues}.
+     */
+    @NonNull
+    protected abstract ContentValues mapToContentValues(@NonNull T object);
+
+    /**
+     * {@inheritDoc}
+     */
+    @NonNull
+    @Override
+    public PutResult performPut(@NonNull StorIOContentResolver storIOContentResolver, @NonNull T object) {
+        final UpdateQuery updateQuery = mapToUpdateQuery(object);
+
+        final Query query = Query.builder()
+                .uri(updateQuery.uri())
+                .where(nullableString(updateQuery.where()))
+                .whereArgs((Object[]) nullableArrayOfStrings(updateQuery.whereArgs()))
+                .build();
+
+        final Cursor cursor = storIOContentResolver.internal().query(query);
+
+        try {
+            final ContentValues contentValues = mapToContentValues(object);
+
+            if (cursor == null || cursor.getCount() == 0) {
+                final InsertQuery insertQuery = mapToInsertQuery(object);
+                final Uri insertedUri = storIOContentResolver.internal().insert(insertQuery, contentValues);
+                return PutResult.newInsertResult(insertedUri, insertQuery.uri());
+            } else {
+                final int numberOfRowsUpdated = storIOContentResolver.internal().update(updateQuery, contentValues);
+                return PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.uri());
+            }
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPut.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPut.java
new file mode 100644
index 0000000..293c7a5
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPut.java
@@ -0,0 +1,83 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.content.ContentValues;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.operations.PreparedOperation;
+
+import java.util.Collection;
+
+/**
+ * Represents an Operation for {@link StorIOContentResolver} which performs insert or update data
+ * in {@link android.content.ContentProvider}.
+ *
+ */
+public abstract class PreparedPut<Result> implements PreparedOperation<Result> {
+
+    @NonNull
+    protected final StorIOContentResolver storIOContentResolver;
+
+    protected PreparedPut(@NonNull StorIOContentResolver storIOContentResolver) {
+        this.storIOContentResolver = storIOContentResolver;
+    }
+
+    /**
+     * Builder for {@link PreparedPut}.
+     */
+    public static final class Builder {
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        public Builder(@NonNull StorIOContentResolver storIOContentResolver) {
+            this.storIOContentResolver = storIOContentResolver;
+        }
+
+        /**
+         * Prepares Put Operation that should put one object.
+         *
+         * @param object object to put.
+         * @param <T>    type of object.
+         * @return builder for {@link PreparedPutObject}.
+         */
+        @NonNull
+        public <T> PreparedPutObject.Builder<T> object(@NonNull T object) {
+            return new PreparedPutObject.Builder<T>(storIOContentResolver, object);
+        }
+
+        /**
+         * Prepares Put Operation that should put multiple objects.
+         *
+         * @param objects objects to put.
+         * @param <T>     type of objects.
+         * @return builder for {@link PreparedPutCollectionOfObjects}.
+         */
+        @NonNull
+        public <T> PreparedPutCollectionOfObjects.Builder<T> objects(@NonNull Collection<T> objects) {
+            return new PreparedPutCollectionOfObjects.Builder<T>(storIOContentResolver, objects);
+        }
+
+        /**
+         * Prepares Put Operation that should put one instance of {@link ContentValues}.
+         *
+         * @param contentValues non-null content values to put.
+         * @return builder for {@link PreparedPutContentValues}.
+         */
+        @NonNull
+        public PreparedPutContentValues.Builder contentValues(@NonNull ContentValues contentValues) {
+            return new PreparedPutContentValues.Builder(storIOContentResolver, contentValues);
+        }
+
+        /**
+         * Prepares Put Operation that should put several instances of {@link ContentValues}.
+         *
+         * @param contentValues non-null collection of {@link ContentValues}.
+         * @return builder for {@link PreparedPutContentValuesIterable}.
+         */
+        @NonNull
+        public PreparedPutContentValuesIterable.Builder contentValues(@NonNull Iterable<ContentValues> contentValues) {
+            return new PreparedPutContentValuesIterable.Builder(storIOContentResolver, contentValues);
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutCollectionOfObjects.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutCollectionOfObjects.java
new file mode 100644
index 0000000..7729881
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutCollectionOfObjects.java
@@ -0,0 +1,182 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Put Operation for collection of objects.
+ *
+ * @param <T> type of objects.
+ */
+public final class PreparedPutCollectionOfObjects<T> extends PreparedPut<PutResults<T>> {
+
+    @NonNull
+    private final Collection<T> objects;
+
+    @Nullable
+    private final PutResolver<T> explicitPutResolver;
+
+    PreparedPutCollectionOfObjects(@NonNull StorIOContentResolver storIOContentResolver,
+                                   @NonNull Collection<T> objects,
+                                   @Nullable PutResolver<T> explicitPutResolver) {
+        super(storIOContentResolver);
+        this.objects = objects;
+        this.explicitPutResolver = explicitPutResolver;
+    }
+
+    /**
+     * Executes Put Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null result of Put Operation.
+     */
+    @SuppressWarnings("unchecked")
+    @WorkerThread
+    @NonNull
+    @Override
+    public PutResults<T> executeAsBlocking() {
+        final StorIOContentResolver.Internal internal = storIOContentResolver.internal();
+
+        // Nullable
+        final List<SimpleImmutableEntry<T, PutResolver<T>>> objectsAndPutResolvers;
+
+        if (explicitPutResolver != null) {
+            objectsAndPutResolvers = null;
+        } else {
+            objectsAndPutResolvers = new ArrayList<SimpleImmutableEntry<T, PutResolver<T>>>(objects.size());
+
+            for (final T object : objects) {
+                final ContentResolverTypeMapping<T> typeMapping
+                        = (ContentResolverTypeMapping<T>) internal.typeMapping(object.getClass());
+
+                if (typeMapping == null) {
+                    throw new IllegalStateException("One of the objects from the collection does not have type mapping: " +
+                            "object = " + object + ", object.class = " + object.getClass() + "," +
+                            "ContentProvider was not affected by this operation, please add type mapping for this type");
+                }
+
+                objectsAndPutResolvers.add(new SimpleImmutableEntry<T, PutResolver<T>>(
+                        object,
+                        typeMapping.putResolver()
+                ));
+            }
+        }
+
+        final Map<T, PutResult> results = new HashMap<T, PutResult>(objects.size());
+
+        if (explicitPutResolver != null) {
+            for (final T object : objects) {
+                final PutResult putResult = explicitPutResolver.performPut(storIOContentResolver, object);
+                results.put(object, putResult);
+            }
+        } else {
+            for (final SimpleImmutableEntry<T, PutResolver<T>> objectAndPutResolver : objectsAndPutResolvers) {
+                final T object = objectAndPutResolver.getKey();
+                final PutResolver<T> putResolver = objectAndPutResolver.getValue();
+
+                final PutResult putResult = putResolver.performPut(storIOContentResolver, object);
+                results.put(object, putResult);
+            }
+        }
+
+        return PutResults.newInstance(results);
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Put Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * put only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Put Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<PutResults<T>> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedPutCollectionOfObjects}.
+     *
+     * @param <T> type of objects to put.
+     */
+    public static final class Builder<T> {
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        @NonNull
+        private final Collection<T> objects;
+
+        @Nullable
+        private PutResolver<T> putResolver;
+
+        public Builder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Collection<T> objects) {
+            this.storIOContentResolver = storIOContentResolver;
+            this.objects = objects;
+        }
+
+        /**
+         * Optional: Specifies resolver for Put Operation
+         * that should define behavior of Put Operation: insert or update
+         * of the objects.
+         * <p/>
+         * Can be set via {@link ContentResolverTypeMapping},
+         * If value is not set via {@link ContentResolverTypeMapping}
+         * or explicitly -> exception will be thrown.
+         *
+         * @param putResolver nullable resolver for Put Operation.
+         * @return builder.
+         */
+        @NonNull
+        public Builder<T> withPutResolver(@NonNull PutResolver<T> putResolver) {
+            this.putResolver = putResolver;
+            return this;
+        }
+
+        /**
+         * Builds new instance of {@link PreparedPutCollectionOfObjects}.
+         *
+         * @return new instance of {@link PreparedPutCollectionOfObjects}.
+         */
+        @NonNull
+        public PreparedPutCollectionOfObjects<T> prepare() {
+            return new PreparedPutCollectionOfObjects<T>(
+                    storIOContentResolver,
+                    objects,
+                    putResolver
+            );
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValues.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValues.java
new file mode 100644
index 0000000..a556931
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValues.java
@@ -0,0 +1,151 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.content.ContentValues;
+import android.support.annotation.NonNull;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Put Operation for {@link ContentValues}.
+ */
+public final class PreparedPutContentValues extends PreparedPut<PutResult> {
+
+    @NonNull
+    private final ContentValues contentValues;
+
+    @NonNull
+    private final PutResolver<ContentValues> putResolver;
+
+    PreparedPutContentValues(@NonNull StorIOContentResolver storIOContentResolver,
+                             @NonNull PutResolver<ContentValues> putResolver,
+                             @NonNull ContentValues contentValues) {
+        super(storIOContentResolver);
+        this.contentValues = contentValues;
+        this.putResolver = putResolver;
+    }
+
+    /**
+     * Executes Put Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null result of Put Operation.
+     */
+    @WorkerThread
+    @NonNull
+    @Override
+    public PutResult executeAsBlocking() {
+        return putResolver.performPut(storIOContentResolver, contentValues);
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Put Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * put only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Put Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<PutResult> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedPutContentValues}.
+     * <p/>
+     * Required: You should specify put resolver see {@link #withPutResolver(PutResolver)}.
+     */
+    public static final class Builder {
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        @NonNull
+        private final ContentValues contentValues;
+
+        /**
+         * Creates builder for {@link PreparedPutContentValues}.
+         *
+         * @param storIOContentResolver instance of {@link StorIOContentResolver}.
+         * @param contentValues         some {@link ContentValues} to put.
+         */
+        public Builder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull ContentValues contentValues) {
+            checkNotNull(storIOContentResolver, "Please specify StorIOContentResolver");
+            checkNotNull(contentValues, "Please specify content values");
+
+            this.storIOContentResolver = storIOContentResolver;
+            this.contentValues = contentValues;
+        }
+
+        /**
+         * Required: Specifies resolver for Put Operation.
+         * that should define behavior of Put Operation: insert or update
+         * of the {@link ContentValues}.
+         *
+         * @param putResolver resolver for Put Operation.
+         * @return builder.
+         */
+        @NonNull
+        public CompleteBuilder withPutResolver(@NonNull PutResolver<ContentValues> putResolver) {
+            checkNotNull(putResolver, "Please specify PutResolver");
+            return new CompleteBuilder(storIOContentResolver, contentValues, putResolver);
+        }
+    }
+
+    /**
+     * Compile-time safe part of builder for {@link PreparedPutContentValues}.
+     */
+    public static final class CompleteBuilder {
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        @NonNull
+        private final ContentValues contentValues;
+
+        @NonNull
+        private final PutResolver<ContentValues> putResolver;
+
+        CompleteBuilder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull ContentValues contentValues, @NonNull PutResolver<ContentValues> putResolver) {
+            this.storIOContentResolver = storIOContentResolver;
+            this.contentValues = contentValues;
+            this.putResolver = putResolver;
+        }
+
+        /**
+         * Builds instance of {@link PreparedPutContentValues}.
+         *
+         * @return instance of {@link PreparedPutContentValues}.
+         */
+        @NonNull
+        public PreparedPutContentValues prepare() {
+            return new PreparedPutContentValues(
+                    storIOContentResolver,
+                    putResolver,
+                    contentValues
+            );
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValuesIterable.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValuesIterable.java
new file mode 100644
index 0000000..5aed403
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValuesIterable.java
@@ -0,0 +1,154 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.content.ContentValues;
+import android.support.annotation.NonNull;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Put Operation to perform put multiple {@link ContentValues}
+ * into {@link StorIOContentResolver}.
+ */
+public final class PreparedPutContentValuesIterable extends PreparedPut<PutResults<ContentValues>> {
+
+    @NonNull
+    private final Iterable<ContentValues> contentValues;
+
+    @NonNull
+    private final PutResolver<ContentValues> putResolver;
+
+    PreparedPutContentValuesIterable(@NonNull StorIOContentResolver storIOContentResolver,
+                                     @NonNull PutResolver<ContentValues> putResolver,
+                                     @NonNull Iterable<ContentValues> contentValues) {
+        super(storIOContentResolver);
+        this.contentValues = contentValues;
+        this.putResolver = putResolver;
+    }
+
+    /**
+     * Executes Put Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null results of Put Operation.
+     */
+    @WorkerThread
+    @NonNull
+    @Override
+    public PutResults<ContentValues> executeAsBlocking() {
+        final Map<ContentValues, PutResult> putResultsMap = new HashMap<ContentValues, PutResult>();
+
+        for (final ContentValues cv : contentValues) {
+            final PutResult putResult = putResolver.performPut(storIOContentResolver, cv);
+            putResultsMap.put(cv, putResult);
+        }
+
+        return PutResults.newInstance(putResultsMap);
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Put Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * put only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Put Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<PutResults<ContentValues>> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedPutContentValuesIterable}.
+     * <p/>
+     * Required: You should specify query see {@link #withPutResolver(PutResolver)}.
+     */
+    public static final class Builder {
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        @NonNull
+        private final Iterable<ContentValues> contentValues;
+
+        public Builder(@NonNull StorIOContentResolver storIOContentResolver,
+                       @NonNull Iterable<ContentValues> contentValues) {
+            this.storIOContentResolver = storIOContentResolver;
+            this.contentValues = contentValues;
+        }
+
+        /**
+         * Required: Specifies resolver for Put Operation
+         * that should define behavior of Put Operation: insert or update
+         * of the {@link ContentValues}.
+         *
+         * @param putResolver resolver for Put Operation.
+         * @return builder.
+         */
+        @NonNull
+        public CompleteBuilder withPutResolver(@NonNull PutResolver<ContentValues> putResolver) {
+            checkNotNull(putResolver, "Please specify PutResolver");
+            return new CompleteBuilder(storIOContentResolver, contentValues, putResolver);
+        }
+    }
+
+    /**
+     * Compile-time safe part of builder for {@link PreparedPutContentValuesIterable}.
+     */
+    public static final class CompleteBuilder {
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        @NonNull
+        private final Iterable<ContentValues> contentValues;
+
+        @NonNull
+        private final PutResolver<ContentValues> putResolver;
+
+        CompleteBuilder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull Iterable<ContentValues> contentValues, @NonNull PutResolver<ContentValues> putResolver) {
+            this.storIOContentResolver = storIOContentResolver;
+            this.contentValues = contentValues;
+            this.putResolver = putResolver;
+        }
+
+        /**
+         * Builds instance of {@link PreparedPutContentValuesIterable}.
+         *
+         * @return instance of {@link PreparedPutContentValuesIterable}.
+         */
+        @NonNull
+        public PreparedPutContentValuesIterable prepare() {
+            return new PreparedPutContentValuesIterable(
+                    storIOContentResolver,
+                    putResolver,
+                    contentValues
+            );
+        }
+    }
+}
\ No newline at end of file
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutObject.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutObject.java
new file mode 100644
index 0000000..3c05e21
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutObject.java
@@ -0,0 +1,148 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Put Operation to perform put object
+ * into {@link StorIOContentResolver}.
+ *
+ * @param <T> type of the object.
+ */
+public final class PreparedPutObject<T> extends PreparedPut<PutResult> {
+
+    @NonNull
+    private final T object;
+
+    @Nullable
+    private final PutResolver<T> explicitPutResolver;
+
+    PreparedPutObject(@NonNull StorIOContentResolver storIOContentResolver,
+                      @Nullable PutResolver<T> explicitPutResolver,
+                      @NonNull T object) {
+        super(storIOContentResolver);
+        this.object = object;
+        this.explicitPutResolver = explicitPutResolver;
+    }
+
+    /**
+     * Executes Put Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null results of Put Operation.
+     */
+    @SuppressWarnings("unchecked")
+    @WorkerThread
+    @NonNull
+    @Override
+    public PutResult executeAsBlocking() {
+        final PutResolver<T> putResolver;
+
+        if (explicitPutResolver != null) {
+            putResolver = explicitPutResolver;
+        } else {
+            final ContentResolverTypeMapping<T> typeMapping
+                    = storIOContentResolver.internal().typeMapping((Class<T>) object.getClass());
+
+            if (typeMapping == null) {
+                throw new IllegalStateException("Object does not have type mapping: " +
+                        "object = " + object + ", object.class = " + object.getClass() + "," +
+                        "ContentProvider was not affected by this operation, please add type mapping for this type");
+            }
+
+            putResolver = typeMapping.putResolver();
+        }
+
+        return putResolver.performPut(storIOContentResolver, object);
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Put Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * put only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Put Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<PutResult> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedPutObject}.
+     *
+     * @param <T> type of object.
+     */
+    public static final class Builder<T> {
+
+        @NonNull
+        private final StorIOContentResolver storIOContentResolver;
+
+        @NonNull
+        private final T object;
+
+        private PutResolver<T> putResolver;
+
+        public Builder(@NonNull StorIOContentResolver storIOContentResolver, @NonNull T object) {
+            this.storIOContentResolver = storIOContentResolver;
+            this.object = object;
+        }
+
+        /**
+         * Optional: Specifies resolver for Put Operation
+         * that should define behavior of Put Operation: insert or update
+         * of the object.
+         * <p/>
+         * Can be set via {@link ContentResolverTypeMapping},
+         * If value is not set via {@link ContentResolverTypeMapping}
+         * or explicitly -> exception will be thrown.
+         *
+         * @param putResolver nullable resolver for Put Operation.
+         * @return builder.
+         */
+        @NonNull
+        public Builder<T> withPutResolver(@Nullable PutResolver<T> putResolver) {
+            this.putResolver = putResolver;
+            return this;
+        }
+
+        /**
+         * Builds instance of {@link PreparedPutObject}.
+         *
+         * @return instance of {@link PreparedPutObject}.
+         */
+        @NonNull
+        public PreparedPutObject<T> prepare() {
+            return new PreparedPutObject<T>(
+                    storIOContentResolver,
+                    putResolver,
+                    object
+            );
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PutResolver.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PutResolver.java
new file mode 100644
index 0000000..37db1e9
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PutResolver.java
@@ -0,0 +1,25 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+
+/**
+ * Defines behavior of Put Operation (insert or update).
+ *
+ * @param <T> type of objects to put.
+ * @see DefaultPutResolver
+ */
+public abstract class PutResolver<T> {
+
+    /**
+     * Performs Put Operation of some {@link android.content.ContentValues}
+     * into {@link StorIOContentResolver}.
+     *
+     * @param storIOContentResolver instance of {@link StorIOContentResolver}.
+     * @param object                non-null object of required type to put.
+     * @return non-null result of Put Operation.
+     */
+    @NonNull
+    public abstract PutResult performPut(@NonNull StorIOContentResolver storIOContentResolver, @NonNull T object);
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PutResult.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PutResult.java
new file mode 100644
index 0000000..d9dda0f
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PutResult.java
@@ -0,0 +1,155 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+/**
+ * Immutable container for single result of Put Operation.
+ */
+public final class PutResult {
+
+    @Nullable
+    private final Uri insertedUri;
+
+    @Nullable
+    private final Integer numberOfRowsUpdated;
+
+    @NonNull
+    private final Uri affectedUri;
+
+    private PutResult(@Nullable Uri insertedUri, @Nullable Integer numberOfRowsUpdated, @NonNull Uri affectedUri) {
+        this.insertedUri = insertedUri;
+        this.numberOfRowsUpdated = numberOfRowsUpdated;
+        this.affectedUri = affectedUri;
+    }
+
+    /**
+     * Creates {@link PutResult} for insert.
+     *
+     * @param insertedUri Uri of inserted row.
+     * @param affectedUri Uri that was affected by insert.
+     * @return new {@link PutResult} instance.
+     */
+    @NonNull
+    public static PutResult newInsertResult(@NonNull Uri insertedUri, @NonNull Uri affectedUri) {
+        return new PutResult(insertedUri, null, affectedUri);
+    }
+
+    /**
+     * Creates {@link PutResult} for update.
+     *
+     * @param numberOfRowsUpdated number of rows that were updated.
+     * @param affectedUri         Uri that was affected by update.
+     * @return new {@link PutResult} instance.
+     */
+    @NonNull
+    public static PutResult newUpdateResult(int numberOfRowsUpdated, @NonNull Uri affectedUri) {
+        return new PutResult(null, numberOfRowsUpdated, affectedUri);
+    }
+
+    /**
+     * Checks whether result of Put Operation was "insert".
+     *
+     * @return {@code true} if something was inserted into
+     * {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver},
+     * {@code false} otherwise.
+     */
+    public boolean wasInserted() {
+        return insertedUri != null;
+    }
+
+    /**
+     * Checks whether result of Put Operation was NOT "insert".
+     *
+     * @return {@code true} if nothing was inserted
+     * into {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver},
+     * {@code false} if something was inserted.
+     */
+    public boolean wasNotInserted() {
+        return !wasInserted();
+    }
+
+    /**
+     * Checks whether result of Put Operation was "update".
+     *
+     * @return {@code true} if something was updated in
+     * {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver},
+     * {@code false} otherwise.
+     */
+    public boolean wasUpdated() {
+        return numberOfRowsUpdated != null;
+    }
+
+    /**
+     * Checks whether result of Put Operation was NOT "update".
+     *
+     * @return {@code true} if nothing was updated
+     * in {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver},
+     * {@code false} if something was updated.
+     */
+    public boolean wasNotUpdated() {
+        return !wasUpdated();
+    }
+
+    /**
+     * Gets id of inserted row.
+     *
+     * @return null if nothing was inserted or id of inserted row.
+     */
+    @Nullable
+    public Uri insertedUri() {
+        return insertedUri;
+    }
+
+    /**
+     * Gets number of updated rows.
+     *
+     * @return null if nothing was updated or number of updated rows.
+     */
+    @Nullable
+    public Integer numberOfRowsUpdated() {
+        return numberOfRowsUpdated;
+    }
+
+    /**
+     * Gets Uri that was affected by this Put.
+     *
+     * @return non-null affected Uri.
+     */
+    @NonNull
+    public Uri affectedUri() {
+        return affectedUri;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        PutResult putResult = (PutResult) o;
+
+        if (insertedUri != null ? !insertedUri.equals(putResult.insertedUri) : putResult.insertedUri != null)
+            return false;
+        if (numberOfRowsUpdated != null ? !numberOfRowsUpdated.equals(putResult.numberOfRowsUpdated) : putResult.numberOfRowsUpdated != null)
+            return false;
+        return affectedUri.equals(putResult.affectedUri);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = insertedUri != null ? insertedUri.hashCode() : 0;
+        result = 31 * result + (numberOfRowsUpdated != null ? numberOfRowsUpdated.hashCode() : 0);
+        result = 31 * result + affectedUri.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "PutResult{" +
+                "insertedUri=" + insertedUri +
+                ", numberOfRowsUpdated=" + numberOfRowsUpdated +
+                ", affectedUri=" + affectedUri +
+                '}';
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PutResults.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PutResults.java
new file mode 100644
index 0000000..a798397
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/operations/put/PutResults.java
@@ -0,0 +1,125 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Immutable container for results of Put Operation of collection of objects.
+ *
+ * @param <T> type of objects.
+ */
+public final class PutResults<T> {
+
+    @NonNull
+    private final Map<T, PutResult> results;
+
+    @Nullable
+    private volatile Integer numberOfInsertsCache;
+
+    @Nullable
+    private volatile Integer numberOfUpdatesCache;
+
+    private PutResults(@NonNull Map<T, PutResult> putResults) {
+        this.results = Collections.unmodifiableMap(putResults);
+    }
+
+    /**
+     * Creates new instance of {@link PutResults}.
+     *
+     * @param putResults results of Put Operation.
+     * @param <T>        type of objects.
+     * @return immutable instance of {@link PutResults}.
+     */
+    @NonNull
+    public static <T> PutResults<T> newInstance(@NonNull Map<T, PutResult> putResults) {
+        return new PutResults<T>(putResults);
+    }
+
+    /**
+     * Returns immutable Map of pairs {@code (object, PutResult)}.
+     *
+     * @return immutable Map of pairs {@code (object, PutResult)}.
+     */
+    @NonNull
+    public Map<T, PutResult> results() {
+        return results;
+    }
+
+    /**
+     * Returns number of inserts from all {@link #results()}.
+     *
+     * @return number of inserts from all {@link #results()}.
+     */
+    public int numberOfInserts() {
+        final Integer cachedValue = numberOfInsertsCache;
+
+        if (cachedValue != null) {
+            return cachedValue;
+        }
+
+        int numberOfInserts = 0;
+
+        for (T object : results.keySet()) {
+            if (results.get(object).wasInserted()) {
+                numberOfInserts++;
+            }
+        }
+
+        numberOfInsertsCache = numberOfInserts;
+
+        return numberOfInserts;
+    }
+
+    /**
+     * Returns number of updates from all {@link #results()}.
+     *
+     * @return number of updates from all {@link #results()}.
+     */
+    public int numberOfUpdates() {
+        final Integer cachedValue = numberOfUpdatesCache;
+
+        if (cachedValue != null) {
+            return cachedValue;
+        }
+
+        int numberOfUpdates = 0;
+
+        for (T object : results.keySet()) {
+            final PutResult putResult = results.get(object);
+
+            if (putResult.wasUpdated()) {
+                //noinspection ConstantConditions
+                numberOfUpdates += putResult.numberOfRowsUpdated();
+            }
+        }
+
+        numberOfUpdatesCache = numberOfUpdates;
+
+        return numberOfUpdates;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        PutResults<?> that = (PutResults<?>) o;
+
+        return results.equals(that.results);
+    }
+
+    @Override
+    public int hashCode() {
+        return results.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "PutResults{" +
+                "results=" + results +
+                '}';
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/DeleteQuery.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/DeleteQuery.java
new file mode 100644
index 0000000..a80fcb5
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/DeleteQuery.java
@@ -0,0 +1,219 @@
+package com.pushtorefresh.storio.contentresolver.queries;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.List;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+import static com.pushtorefresh.storio.internal.Queries.nonNullString;
+import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullList;
+import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullListOfStrings;
+
+/**
+ * Delete query for {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver}.
+ * <p>
+ * Instances of this class are Immutable.
+ */
+public final class DeleteQuery {
+
+    @NonNull
+    private final Uri uri;
+
+    @NonNull
+    private final String where;
+
+    @NonNull
+    private final List<String> whereArgs;
+
+    /**
+     * Please use {@link com.pushtorefresh.storio.contentresolver.queries.DeleteQuery.Builder}
+     * instead of constructor.
+     */
+    private DeleteQuery(@NonNull Uri uri, @Nullable String where, @Nullable List<String> whereArgs) {
+        this.uri = uri;
+        this.where = nonNullString(where);
+        this.whereArgs = unmodifiableNonNullList(whereArgs);
+    }
+
+    /**
+     * Gets full {@code URI} to query, including a row ID (if a specific record is requested).
+     *
+     * @return non-null URI to query.
+     */
+    @NonNull
+    public Uri uri() {
+        return uri;
+    }
+
+    /**
+     * Gets {@code WHERE} clause.
+     * <p>
+     * An optional restriction to apply to rows when deleting.
+     * <p>
+     * If empty — all rows will be deleted.
+     *
+     * @return non-null {@code WHERE} clause.
+     */
+    @NonNull
+    public String where() {
+        return where;
+    }
+
+    /**
+     * Gets optional immutable list of arguments for {@link #where()} clause.
+     *
+     * @return non-null, immutable list of arguments for {@code WHERE} clause.
+     */
+    @NonNull
+    public List<String> whereArgs() {
+        return whereArgs;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        DeleteQuery that = (DeleteQuery) o;
+
+        if (!uri.equals(that.uri)) return false;
+        if (!where.equals(that.where)) return false;
+        return whereArgs.equals(that.whereArgs);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = uri.hashCode();
+        result = 31 * result + where.hashCode();
+        result = 31 * result + whereArgs.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "DeleteQuery{" +
+                "uri=" + uri +
+                ", where='" + where + '\'' +
+                ", whereArgs=" + whereArgs +
+                '}';
+    }
+
+    /**
+     * Creates new builder for {@link DeleteQuery}.
+     *
+     * @return non-null instance of {@link DeleteQuery.Builder}.
+     */
+    @NonNull
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link DeleteQuery}.
+     */
+    public static final class Builder {
+
+        /**
+         * Please use {@link DeleteQuery#builder()} instead of this.
+         */
+        Builder() {
+        }
+
+        /**
+         * Required: Specifies uri.
+         *
+         * @param uri full {@code URI} to query, including a row ID
+         *            (if a specific record is requested).
+         * @return builder.
+         * @see DeleteQuery#uri()
+         */
+        @NonNull
+        public CompleteBuilder uri(@NonNull Uri uri) {
+            checkNotNull(uri, "Please specify uri");
+            return new CompleteBuilder(uri);
+        }
+
+        /**
+         * Required: Specifies uri.
+         *
+         * @param uri full {@code URI} to query,
+         *            including a row ID (if a specific record is requested).
+         * @return builder.
+         * @see DeleteQuery#uri()
+         */
+        @NonNull
+        public CompleteBuilder uri(@NonNull String uri) {
+            checkNotNull(uri, "Uri should not be null");
+            return new CompleteBuilder(Uri.parse(uri));
+        }
+    }
+
+    /**
+     * Compile-time safe part of builder for {@link DeleteQuery}.
+     */
+    public static final class CompleteBuilder {
+
+        @NonNull
+        private final Uri uri;
+
+        private String where;
+        private List<String> whereArgs;
+
+        CompleteBuilder(@NonNull Uri uri) {
+            this.uri = uri;
+        }
+
+        /**
+         * Optional: Specifies {@code WHERE} clause.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param where optional restriction to apply to rows when deleting.
+         * @return builder.
+         * @see DeleteQuery#where()
+         */
+        @NonNull
+        public CompleteBuilder where(@Nullable String where) {
+            this.where = where;
+            return this;
+        }
+
+        /**
+         * Optional: Specifies arguments for where clause.
+         * <p>
+         * Passed objects will be immediately converted to list
+         * of {@link String} via calling {@link Object#toString()}.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param whereArgs arguments for {@link DeleteQuery#where}.
+         * @return builder.
+         * @see DeleteQuery#whereArgs()
+         */
+        @NonNull
+        public CompleteBuilder whereArgs(@Nullable Object... whereArgs) {
+            this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
+            return this;
+        }
+
+        /**
+         * Builds new instance of {@link DeleteQuery}.
+         *
+         * @return new instance of {@link DeleteQuery}.
+         */
+        @NonNull
+        public DeleteQuery build() {
+            if (where == null && whereArgs != null && !whereArgs.isEmpty()) {
+                throw new IllegalStateException("You can not use whereArgs without where clause");
+            }
+
+            return new DeleteQuery(
+                    uri,
+                    where,
+                    whereArgs
+            );
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/InsertQuery.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/InsertQuery.java
new file mode 100644
index 0000000..6259b1e
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/InsertQuery.java
@@ -0,0 +1,133 @@
+package com.pushtorefresh.storio.contentresolver.queries;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+
+/**
+ * Insert query for {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver}.
+ * <p/>
+ * Instances of this class are Immutable.
+ */
+public final class InsertQuery {
+
+    @NonNull
+    private final Uri uri;
+
+    /**
+     * Please use {@link com.pushtorefresh.storio.contentresolver.queries.InsertQuery.Builder}
+     * instead of constructor.
+     */
+    private InsertQuery(@NonNull Uri uri) {
+        this.uri = uri;
+    }
+
+    /**
+     * Gets {@code content://} URI of the insertion request.
+     *
+     * @return non-null URI of the insertion request.
+     */
+    @NonNull
+    public Uri uri() {
+        return uri;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        InsertQuery that = (InsertQuery) o;
+
+        return uri.equals(that.uri);
+    }
+
+    @Override
+    public int hashCode() {
+        return uri.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "InsertQuery{" +
+                "uri=" + uri +
+                '}';
+    }
+
+    /**
+     * Creates new builder for {@link InsertQuery}.
+     *
+     * @return non-null instance of {@link InsertQuery.Builder}.
+     */
+    @NonNull
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link InsertQuery}.
+     * <p/>
+     * Yep, it looks stupid with only one parameter — Uri, but think about future,
+     * we can add other things later without breaking the API!
+     */
+    public static final class Builder {
+
+        /**
+         * Please use {@link InsertQuery#builder()} instead of this.
+         */
+        Builder() {
+        }
+
+        /**
+         * Required: Specifies uri.
+         *
+         * @param uri {@code content://} URI of the insertion request.
+         * @return builder.
+         * @see InsertQuery#uri()
+         */
+        @NonNull
+        public CompleteBuilder uri(@NonNull Uri uri) {
+            checkNotNull(uri, "Please specify uri");
+            return new CompleteBuilder(uri);
+        }
+
+        /**
+         * Required: Specifies uri.
+         *
+         * @param uri {@code content://} URI of the insertion request.
+         * @return builder.
+         * @see InsertQuery#uri()
+         */
+        @NonNull
+        public CompleteBuilder uri(@NonNull String uri) {
+            checkNotNull(uri, "Uri should not be null");
+            return new CompleteBuilder(Uri.parse(uri));
+        }
+    }
+
+    /**
+     * Compile-time safe part of builder for {@link DeleteQuery}.
+     */
+    public static final class CompleteBuilder {
+
+        @NonNull
+        private final Uri uri;
+
+        CompleteBuilder(@NonNull Uri uri) {
+            this.uri = uri;
+        }
+
+        /**
+         * Builds {@link InsertQuery} instance with required params.
+         *
+         * @return new {@link InsertQuery} instance.
+         */
+        @NonNull
+        public InsertQuery build() {
+            return new InsertQuery(
+                    uri
+            );
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/Query.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/Query.java
new file mode 100644
index 0000000..1d5dbba
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/Query.java
@@ -0,0 +1,308 @@
+package com.pushtorefresh.storio.contentresolver.queries;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.List;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+import static com.pushtorefresh.storio.internal.Queries.nonNullString;
+import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullList;
+import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullListOfStrings;
+
+/**
+ * Query for {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver}.
+ * <p>
+ * Instances of this class are Immutable.
+ */
+public class Query {
+
+    @NonNull
+    private final Uri uri;
+
+    @NonNull
+    private final List<String> columns;
+
+    @NonNull
+    private final String where;
+
+    @NonNull
+    private final List<String> whereArgs;
+
+    @NonNull
+    private final String sortOrder;
+
+    /**
+     * Please use {@link com.pushtorefresh.storio.contentresolver.queries.Query.Builder}
+     * instead of constructor.
+     */
+    private Query(@NonNull Uri uri, @Nullable List<String> columns, @Nullable String where, @Nullable List<String> whereArgs, @Nullable String sortOrder) {
+        this.uri = uri;
+        this.columns = unmodifiableNonNullList(columns);
+        this.where = nonNullString(where);
+        this.whereArgs = unmodifiableNonNullList(whereArgs);
+        this.sortOrder = nonNullString(sortOrder);
+    }
+
+    /**
+     * Gets URI to query.
+     * <p>
+     * This will be the full URI sent by the client.
+     * If the client is requesting a specific record, the URI will
+     * end in a record number that the implementation should parse and
+     * add to a {@code WHERE} or {@code HAVING} clause,
+     * specifying that {@code _id} value.
+     *
+     * @return non-null URI to query.
+     */
+    @NonNull
+    public Uri uri() {
+        return uri;
+    }
+
+    /**
+     * Gets optional immutable list of columns that should be received.
+     * <p>
+     * If list is empty -> all columns will be received.
+     *
+     * @return non-null, immutable list of columns that should be received.
+     */
+    @NonNull
+    public List<String> columns() {
+        return columns;
+    }
+
+    /**
+     * Gets {@code WHERE} clause.
+     * <p>
+     * Optional filter declaring which rows to return.
+     * <p>
+     * Formatted as an SQL {@code WHERE} clause (excluding the {@code WHERE} itself).
+     * <p>
+     * If it's empty — Query will retrieve all rows for specified URI.
+     *
+     * @return non-null {@code WHERE} clause.
+     */
+    @NonNull
+    public String where() {
+        return where;
+    }
+
+    /**
+     * Gets optional immutable list of arguments for {@link #where()} clause.
+     *
+     * @return non-null, immutable list of arguments for {@code WHERE} clause.
+     */
+    @NonNull
+    public List<String> whereArgs() {
+        return whereArgs;
+    }
+
+    /**
+     * Gets sort order.
+     * <p>
+     * How the rows in the cursor should be sorted.
+     * If empty then the provider is free to define the sort order.
+     *
+     * @return non-null sort order.
+     */
+    @NonNull
+    public String sortOrder() {
+        return sortOrder;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Query query = (Query) o;
+
+        if (!uri.equals(query.uri)) return false;
+        if (!columns.equals(query.columns)) return false;
+        if (!where.equals(query.where)) return false;
+        if (!whereArgs.equals(query.whereArgs)) return false;
+        return sortOrder.equals(query.sortOrder);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = uri.hashCode();
+        result = 31 * result + columns.hashCode();
+        result = 31 * result + where.hashCode();
+        result = 31 * result + whereArgs.hashCode();
+        result = 31 * result + sortOrder.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "Query{" +
+                "uri=" + uri +
+                ", columns=" + columns +
+                ", where='" + where + '\'' +
+                ", whereArgs=" + whereArgs +
+                ", sortOrder='" + sortOrder + '\'' +
+                '}';
+    }
+
+    /**
+     * Creates new builder for {@link Query}.
+     *
+     * @return non-null instance of {@link Query.Builder}.
+     */
+    @NonNull
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link Query}.
+     */
+    public static final class Builder {
+
+        /**
+         * Please use {@link Query#builder()} instead of this.
+         */
+        Builder() {
+        }
+
+        /**
+         * Required: Specifies URI to query.
+         * This will be the full URI sent by the client;
+         * if the client is requesting a specific record,
+         * the URI will end in a record number that the implementation should parse and add to a WHERE or HAVING clause,
+         * specifying that _id value.
+         *
+         * @param uri uri.
+         * @return builder.
+         * @see Query#uri()
+         */
+        @NonNull
+        public CompleteBuilder uri(@NonNull Uri uri) {
+            checkNotNull(uri, "Please specify uri");
+            return new CompleteBuilder(uri);
+        }
+
+        /**
+         * Required: Specifies URI to query.
+         * This will be the full URI sent by the client;
+         * if the client is requesting a specific record,
+         * the URI will end in a record number that the implementation should parse and add to a WHERE or HAVING clause,
+         * specifying that _id value.
+         *
+         * @param uri uri string which will be converted to {@link Uri}.
+         * @return builder.
+         * @see Query#uri()
+         */
+        @NonNull
+        public CompleteBuilder uri(@NonNull String uri) {
+            checkNotNull(uri, "Uri should not be null");
+            return new CompleteBuilder(Uri.parse(uri));
+        }
+    }
+
+    /**
+     * Compile-time safe part of builder for {@link DeleteQuery}.
+     */
+    public static final class CompleteBuilder {
+
+        @NonNull
+        private final Uri uri;
+
+        private List<String> columns;
+
+        private String where;
+
+        private List<String> whereArgs;
+
+        private String sortOrder;
+
+        CompleteBuilder(@NonNull Uri uri) {
+            this.uri = uri;
+        }
+
+        /**
+         * Optional: The list of columns to put into the cursor.
+         * If {@code null} all columns are included.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param columns columns.
+         * @return builder.
+         * @see Query#columns()
+         */
+        @NonNull
+        public CompleteBuilder columns(@Nullable String... columns) {
+            this.columns = unmodifiableNonNullListOfStrings(columns);
+            return this;
+        }
+
+        /**
+         * Optional: A selection criteria to apply when filtering rows.
+         * If {@code null} then all rows are included.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param where where clause.
+         * @return builder.
+         * @see Query#where()
+         */
+        @NonNull
+        public CompleteBuilder where(@Nullable String where) {
+            this.where = where;
+            return this;
+        }
+
+        /**
+         * Optional: Specifies arguments for where clause.
+         * <p>
+         * Passed objects will be immediately converted
+         * to list {@link String} via calling {@link Object#toString()}.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param whereArgs selection arguments.
+         * @return builder.
+         * @see Query#whereArgs()
+         */
+        @NonNull
+        public CompleteBuilder whereArgs(@Nullable Object... whereArgs) {
+            this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
+            return this;
+        }
+
+        /**
+         * Optional: Specifies how the rows in the cursor should be sorted.
+         * If {@code null} then the provider is free to define the sort order.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param sortOrder sort order.
+         * @return builder.
+         * @see Query#sortOrder()
+         */
+        @NonNull
+        public CompleteBuilder sortOrder(@Nullable String sortOrder) {
+            this.sortOrder = sortOrder;
+            return this;
+        }
+
+        /**
+         * Builds new instance of {@link Query}.
+         *
+         * @return new instance of {@link Query}.
+         */
+        @NonNull
+        public Query build() {
+            return new Query(
+                    uri,
+                    columns,
+                    where,
+                    whereArgs,
+                    sortOrder
+            );
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/UpdateQuery.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/UpdateQuery.java
new file mode 100644
index 0000000..f68d279
--- /dev/null
+++ b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/queries/UpdateQuery.java
@@ -0,0 +1,217 @@
+package com.pushtorefresh.storio.contentresolver.queries;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.List;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+import static com.pushtorefresh.storio.internal.Queries.nonNullString;
+import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullList;
+import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullListOfStrings;
+
+/**
+ * Update query for {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver}.
+ * <p/>
+ * Instances of this class are Immutable.
+ */
+public final class UpdateQuery {
+
+    @NonNull
+    private final Uri uri;
+
+    @NonNull
+    private final String where;
+
+    @NonNull
+    private final List<String> whereArgs;
+
+    /**
+     * Please use {@link com.pushtorefresh.storio.contentresolver.queries.UpdateQuery.Builder}
+     * instead of constructor.
+     */
+    private UpdateQuery(@NonNull Uri uri, @Nullable String where, @Nullable List<String> whereArgs) {
+        this.uri = uri;
+        this.where = nonNullString(where);
+        this.whereArgs = unmodifiableNonNullList(whereArgs);
+    }
+
+    /**
+     * Gets {@code content://} URI of the insertion request.
+     * <p/>
+     * This can potentially have a record ID if this is an update request for a specific record.
+     *
+     * @return non-null URI of the update request.
+     */
+    @NonNull
+    public Uri uri() {
+        return uri;
+    }
+
+    /**
+     * Gets {@code WHERE} clause.
+     * <p/>
+     * Optional filter declaring which rows to update.
+     * <p/>
+     * Formatted as an SQL {@code WHERE} clause (excluding the {@code WHERE} itself).
+     * <p/>
+     * If empty — Query will update all rows for specified URI.
+     *
+     * @return non-null {@code WHERE} clause.
+     */
+    @NonNull
+    public String where() {
+        return where;
+    }
+
+    /**
+     * Gets optional immutable list of arguments for {@link #where()} clause.
+     *
+     * @return non-null, immutable list of arguments for {@code WHERE} clause.
+     */
+    @NonNull
+    public List<String> whereArgs() {
+        return whereArgs;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        UpdateQuery that = (UpdateQuery) o;
+
+        if (!uri.equals(that.uri)) return false;
+        if (!where.equals(that.where)) return false;
+        return whereArgs.equals(that.whereArgs);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = uri.hashCode();
+        result = 31 * result + where.hashCode();
+        result = 31 * result + whereArgs.hashCode();
+        return result;
+    }
+
+    /**
+     * Creates new builder for {@link UpdateQuery}.
+     *
+     * @return non-null instance of {@link UpdateQuery.Builder}.
+     */
+    @NonNull
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link UpdateQuery}.
+     */
+    public static final class Builder {
+
+        /**
+         * Please use {@link UpdateQuery#builder()} instead of this.
+         */
+        Builder() {
+        }
+
+        /**
+         * Required: Specifies uri.
+         *
+         * @param uri URI to query.
+         *            This can potentially have a record ID if this is an update
+         *            request for a specific record.
+         * @return builder.
+         * @see UpdateQuery#uri()
+         */
+        @NonNull
+        public CompleteBuilder uri(@NonNull Uri uri) {
+            checkNotNull(uri, "Please specify uri");
+            return new CompleteBuilder(uri);
+        }
+
+        /**
+         * Required: Specifies uri.
+         *
+         * @param uri URI to query.
+         *            This can potentially have a record ID if this is an update
+         *            request for a specific record.
+         * @return builder.
+         * @see UpdateQuery#uri()
+         */
+        @NonNull
+        public CompleteBuilder uri(@NonNull String uri) {
+            checkNotNull(uri, "Uri should not be null");
+            return new CompleteBuilder(Uri.parse(uri));
+        }
+    }
+
+    /**
+     * Compile-time safe part of {@link Builder}.
+     */
+    public static final class CompleteBuilder {
+
+        @NonNull
+        private final Uri uri;
+
+        private String where;
+
+        private List<String> whereArgs;
+
+        CompleteBuilder(@NonNull Uri uri) {
+            this.uri = uri;
+        }
+
+        /**
+         * Optional: Specifies where clause.
+         * <p/>
+         * Default value is {@code null}.
+         *
+         * @param where an optional filter to match rows to update.
+         * @return builder.
+         * @see UpdateQuery#where()
+         */
+        @NonNull
+        public CompleteBuilder where(@Nullable String where) {
+            this.where = where;
+            return this;
+        }
+
+        /**
+         * Optional: Specifies arguments for where clause.
+         * <p/>
+         * Passed objects will be immediately converted to
+         * list {@link String} via calling {@link Object#toString()}.
+         * <p/>
+         * Default value is {@code null}.
+         *
+         * @param whereArgs arguments for {@link UpdateQuery#where}.
+         * @return builder.
+         * @see UpdateQuery#whereArgs()
+         */
+        @NonNull
+        public CompleteBuilder whereArgs(@Nullable Object... whereArgs) {
+            this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
+            return this;
+        }
+
+        /**
+         * Builds new instance of {@link UpdateQuery}.
+         *
+         * @return new instance of {@link UpdateQuery}.
+         */
+        @NonNull
+        public UpdateQuery build() {
+            if (where == null && whereArgs != null && !whereArgs.isEmpty()) {
+                throw new IllegalStateException("You can not use whereArgs without where clause");
+            }
+
+            return new UpdateQuery(
+                    uri,
+                    where,
+                    whereArgs
+            );
+        }
+    }
+}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/DeleteQuery.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/DeleteQuery.java
deleted file mode 100644
index 4102040..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/DeleteQuery.java
+++ /dev/null
@@ -1,219 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.query;
-
-import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import java.util.List;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-import static com.pushtorefresh.storio.internal.Queries.nonNullString;
-import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullList;
-import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullListOfStrings;
-
-/**
- * Delete query for {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver}.
- * <p>
- * Instances of this class are Immutable.
- */
-public final class DeleteQuery {
-
-    @NonNull
-    private final Uri uri;
-
-    @NonNull
-    private final String where;
-
-    @NonNull
-    private final List<String> whereArgs;
-
-    /**
-     * Please use {@link com.pushtorefresh.storio.contentresolver.query.DeleteQuery.Builder}
-     * instead of constructor.
-     */
-    private DeleteQuery(@NonNull Uri uri, @Nullable String where, @Nullable List<String> whereArgs) {
-        this.uri = uri;
-        this.where = nonNullString(where);
-        this.whereArgs = unmodifiableNonNullList(whereArgs);
-    }
-
-    /**
-     * Gets full {@code URI} to query, including a row ID (if a specific record is requested).
-     *
-     * @return non-null URI to query.
-     */
-    @NonNull
-    public Uri uri() {
-        return uri;
-    }
-
-    /**
-     * Gets {@code WHERE} clause.
-     * <p>
-     * An optional restriction to apply to rows when deleting.
-     * <p>
-     * If empty — all rows will be deleted.
-     *
-     * @return non-null {@code WHERE} clause.
-     */
-    @NonNull
-    public String where() {
-        return where;
-    }
-
-    /**
-     * Gets optional immutable list of arguments for {@link #where()} clause.
-     *
-     * @return non-null, immutable list of arguments for {@code WHERE} clause.
-     */
-    @NonNull
-    public List<String> whereArgs() {
-        return whereArgs;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        DeleteQuery that = (DeleteQuery) o;
-
-        if (!uri.equals(that.uri)) return false;
-        if (!where.equals(that.where)) return false;
-        return whereArgs.equals(that.whereArgs);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = uri.hashCode();
-        result = 31 * result + where.hashCode();
-        result = 31 * result + whereArgs.hashCode();
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "DeleteQuery{" +
-                "uri=" + uri +
-                ", where='" + where + '\'' +
-                ", whereArgs=" + whereArgs +
-                '}';
-    }
-
-    /**
-     * Creates new builder for {@link DeleteQuery}.
-     *
-     * @return non-null instance of {@link DeleteQuery.Builder}.
-     */
-    @NonNull
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    /**
-     * Builder for {@link DeleteQuery}.
-     */
-    public static final class Builder {
-
-        /**
-         * Please use {@link DeleteQuery#builder()} instead of this.
-         */
-        Builder() {
-        }
-
-        /**
-         * Required: Specifies uri.
-         *
-         * @param uri full {@code URI} to query, including a row ID
-         *            (if a specific record is requested).
-         * @return builder.
-         * @see DeleteQuery#uri()
-         */
-        @NonNull
-        public CompleteBuilder uri(@NonNull Uri uri) {
-            checkNotNull(uri, "Please specify uri");
-            return new CompleteBuilder(uri);
-        }
-
-        /**
-         * Required: Specifies uri.
-         *
-         * @param uri full {@code URI} to query,
-         *            including a row ID (if a specific record is requested).
-         * @return builder.
-         * @see DeleteQuery#uri()
-         */
-        @NonNull
-        public CompleteBuilder uri(@NonNull String uri) {
-            checkNotNull(uri, "Uri should not be null");
-            return new CompleteBuilder(Uri.parse(uri));
-        }
-    }
-
-    /**
-     * Compile-time safe part of builder for {@link DeleteQuery}.
-     */
-    public static final class CompleteBuilder {
-
-        @NonNull
-        private final Uri uri;
-
-        private String where;
-        private List<String> whereArgs;
-
-        CompleteBuilder(@NonNull Uri uri) {
-            this.uri = uri;
-        }
-
-        /**
-         * Optional: Specifies {@code WHERE} clause.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param where optional restriction to apply to rows when deleting.
-         * @return builder.
-         * @see DeleteQuery#where()
-         */
-        @NonNull
-        public CompleteBuilder where(@Nullable String where) {
-            this.where = where;
-            return this;
-        }
-
-        /**
-         * Optional: Specifies arguments for where clause.
-         * <p>
-         * Passed objects will be immediately converted to list
-         * of {@link String} via calling {@link Object#toString()}.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param whereArgs arguments for {@link DeleteQuery#where}.
-         * @return builder.
-         * @see DeleteQuery#whereArgs()
-         */
-        @NonNull
-        public CompleteBuilder whereArgs(@Nullable Object... whereArgs) {
-            this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
-            return this;
-        }
-
-        /**
-         * Builds new instance of {@link DeleteQuery}.
-         *
-         * @return new instance of {@link DeleteQuery}.
-         */
-        @NonNull
-        public DeleteQuery build() {
-            if (where == null && whereArgs != null && !whereArgs.isEmpty()) {
-                throw new IllegalStateException("You can not use whereArgs without where clause");
-            }
-
-            return new DeleteQuery(
-                    uri,
-                    where,
-                    whereArgs
-            );
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/InsertQuery.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/InsertQuery.java
deleted file mode 100644
index 14a9969..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/InsertQuery.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.query;
-
-import android.net.Uri;
-import android.support.annotation.NonNull;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-
-/**
- * Insert query for {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver}.
- * <p/>
- * Instances of this class are Immutable.
- */
-public final class InsertQuery {
-
-    @NonNull
-    private final Uri uri;
-
-    /**
-     * Please use {@link com.pushtorefresh.storio.contentresolver.query.InsertQuery.Builder}
-     * instead of constructor.
-     */
-    private InsertQuery(@NonNull Uri uri) {
-        this.uri = uri;
-    }
-
-    /**
-     * Gets {@code content://} URI of the insertion request.
-     *
-     * @return non-null URI of the insertion request.
-     */
-    @NonNull
-    public Uri uri() {
-        return uri;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        InsertQuery that = (InsertQuery) o;
-
-        return uri.equals(that.uri);
-    }
-
-    @Override
-    public int hashCode() {
-        return uri.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        return "InsertQuery{" +
-                "uri=" + uri +
-                '}';
-    }
-
-    /**
-     * Creates new builder for {@link InsertQuery}.
-     *
-     * @return non-null instance of {@link InsertQuery.Builder}.
-     */
-    @NonNull
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    /**
-     * Builder for {@link InsertQuery}.
-     * <p/>
-     * Yep, it looks stupid with only one parameter — Uri, but think about future,
-     * we can add other things later without breaking the API!
-     */
-    public static final class Builder {
-
-        /**
-         * Please use {@link InsertQuery#builder()} instead of this.
-         */
-        Builder() {
-        }
-
-        /**
-         * Required: Specifies uri.
-         *
-         * @param uri {@code content://} URI of the insertion request.
-         * @return builder.
-         * @see InsertQuery#uri()
-         */
-        @NonNull
-        public CompleteBuilder uri(@NonNull Uri uri) {
-            checkNotNull(uri, "Please specify uri");
-            return new CompleteBuilder(uri);
-        }
-
-        /**
-         * Required: Specifies uri.
-         *
-         * @param uri {@code content://} URI of the insertion request.
-         * @return builder.
-         * @see InsertQuery#uri()
-         */
-        @NonNull
-        public CompleteBuilder uri(@NonNull String uri) {
-            checkNotNull(uri, "Uri should not be null");
-            return new CompleteBuilder(Uri.parse(uri));
-        }
-    }
-
-    /**
-     * Compile-time safe part of builder for {@link DeleteQuery}.
-     */
-    public static final class CompleteBuilder {
-
-        @NonNull
-        private final Uri uri;
-
-        CompleteBuilder(@NonNull Uri uri) {
-            this.uri = uri;
-        }
-
-        /**
-         * Builds {@link InsertQuery} instance with required params.
-         *
-         * @return new {@link InsertQuery} instance.
-         */
-        @NonNull
-        public InsertQuery build() {
-            return new InsertQuery(
-                    uri
-            );
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/Query.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/Query.java
deleted file mode 100644
index cb31b56..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/Query.java
+++ /dev/null
@@ -1,308 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.query;
-
-import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import java.util.List;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-import static com.pushtorefresh.storio.internal.Queries.nonNullString;
-import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullList;
-import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullListOfStrings;
-
-/**
- * Query for {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver}.
- * <p>
- * Instances of this class are Immutable.
- */
-public class Query {
-
-    @NonNull
-    private final Uri uri;
-
-    @NonNull
-    private final List<String> columns;
-
-    @NonNull
-    private final String where;
-
-    @NonNull
-    private final List<String> whereArgs;
-
-    @NonNull
-    private final String sortOrder;
-
-    /**
-     * Please use {@link com.pushtorefresh.storio.contentresolver.query.Query.Builder}
-     * instead of constructor.
-     */
-    private Query(@NonNull Uri uri, @Nullable List<String> columns, @Nullable String where, @Nullable List<String> whereArgs, @Nullable String sortOrder) {
-        this.uri = uri;
-        this.columns = unmodifiableNonNullList(columns);
-        this.where = nonNullString(where);
-        this.whereArgs = unmodifiableNonNullList(whereArgs);
-        this.sortOrder = nonNullString(sortOrder);
-    }
-
-    /**
-     * Gets URI to query.
-     * <p>
-     * This will be the full URI sent by the client.
-     * If the client is requesting a specific record, the URI will
-     * end in a record number that the implementation should parse and
-     * add to a {@code WHERE} or {@code HAVING} clause,
-     * specifying that {@code _id} value.
-     *
-     * @return non-null URI to query.
-     */
-    @NonNull
-    public Uri uri() {
-        return uri;
-    }
-
-    /**
-     * Gets optional immutable list of columns that should be received.
-     * <p>
-     * If list is empty -> all columns will be received.
-     *
-     * @return non-null, immutable list of columns that should be received.
-     */
-    @NonNull
-    public List<String> columns() {
-        return columns;
-    }
-
-    /**
-     * Gets {@code WHERE} clause.
-     * <p>
-     * Optional filter declaring which rows to return.
-     * <p>
-     * Formatted as an SQL {@code WHERE} clause (excluding the {@code WHERE} itself).
-     * <p>
-     * If it's empty — Query will retrieve all rows for specified URI.
-     *
-     * @return non-null {@code WHERE} clause.
-     */
-    @NonNull
-    public String where() {
-        return where;
-    }
-
-    /**
-     * Gets optional immutable list of arguments for {@link #where()} clause.
-     *
-     * @return non-null, immutable list of arguments for {@code WHERE} clause.
-     */
-    @NonNull
-    public List<String> whereArgs() {
-        return whereArgs;
-    }
-
-    /**
-     * Gets sort order.
-     * <p>
-     * How the rows in the cursor should be sorted.
-     * If empty then the provider is free to define the sort order.
-     *
-     * @return non-null sort order.
-     */
-    @NonNull
-    public String sortOrder() {
-        return sortOrder;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        Query query = (Query) o;
-
-        if (!uri.equals(query.uri)) return false;
-        if (!columns.equals(query.columns)) return false;
-        if (!where.equals(query.where)) return false;
-        if (!whereArgs.equals(query.whereArgs)) return false;
-        return sortOrder.equals(query.sortOrder);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = uri.hashCode();
-        result = 31 * result + columns.hashCode();
-        result = 31 * result + where.hashCode();
-        result = 31 * result + whereArgs.hashCode();
-        result = 31 * result + sortOrder.hashCode();
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "Query{" +
-                "uri=" + uri +
-                ", columns=" + columns +
-                ", where='" + where + '\'' +
-                ", whereArgs=" + whereArgs +
-                ", sortOrder='" + sortOrder + '\'' +
-                '}';
-    }
-
-    /**
-     * Creates new builder for {@link Query}.
-     *
-     * @return non-null instance of {@link Query.Builder}.
-     */
-    @NonNull
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    /**
-     * Builder for {@link Query}.
-     */
-    public static final class Builder {
-
-        /**
-         * Please use {@link Query#builder()} instead of this.
-         */
-        Builder() {
-        }
-
-        /**
-         * Required: Specifies URI to query.
-         * This will be the full URI sent by the client;
-         * if the client is requesting a specific record,
-         * the URI will end in a record number that the implementation should parse and add to a WHERE or HAVING clause,
-         * specifying that _id value.
-         *
-         * @param uri uri.
-         * @return builder.
-         * @see Query#uri()
-         */
-        @NonNull
-        public CompleteBuilder uri(@NonNull Uri uri) {
-            checkNotNull(uri, "Please specify uri");
-            return new CompleteBuilder(uri);
-        }
-
-        /**
-         * Required: Specifies URI to query.
-         * This will be the full URI sent by the client;
-         * if the client is requesting a specific record,
-         * the URI will end in a record number that the implementation should parse and add to a WHERE or HAVING clause,
-         * specifying that _id value.
-         *
-         * @param uri uri string which will be converted to {@link Uri}.
-         * @return builder.
-         * @see Query#uri()
-         */
-        @NonNull
-        public CompleteBuilder uri(@NonNull String uri) {
-            checkNotNull(uri, "Uri should not be null");
-            return new CompleteBuilder(Uri.parse(uri));
-        }
-    }
-
-    /**
-     * Compile-time safe part of builder for {@link DeleteQuery}.
-     */
-    public static final class CompleteBuilder {
-
-        @NonNull
-        private final Uri uri;
-
-        private List<String> columns;
-
-        private String where;
-
-        private List<String> whereArgs;
-
-        private String sortOrder;
-
-        CompleteBuilder(@NonNull Uri uri) {
-            this.uri = uri;
-        }
-
-        /**
-         * Optional: The list of columns to put into the cursor.
-         * If {@code null} all columns are included.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param columns columns.
-         * @return builder.
-         * @see Query#columns()
-         */
-        @NonNull
-        public CompleteBuilder columns(@Nullable String... columns) {
-            this.columns = unmodifiableNonNullListOfStrings(columns);
-            return this;
-        }
-
-        /**
-         * Optional: A selection criteria to apply when filtering rows.
-         * If {@code null} then all rows are included.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param where where clause.
-         * @return builder.
-         * @see Query#where()
-         */
-        @NonNull
-        public CompleteBuilder where(@Nullable String where) {
-            this.where = where;
-            return this;
-        }
-
-        /**
-         * Optional: Specifies arguments for where clause.
-         * <p>
-         * Passed objects will be immediately converted
-         * to list {@link String} via calling {@link Object#toString()}.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param whereArgs selection arguments.
-         * @return builder.
-         * @see Query#whereArgs()
-         */
-        @NonNull
-        public CompleteBuilder whereArgs(@Nullable Object... whereArgs) {
-            this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
-            return this;
-        }
-
-        /**
-         * Optional: Specifies how the rows in the cursor should be sorted.
-         * If {@code null} then the provider is free to define the sort order.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param sortOrder sort order.
-         * @return builder.
-         * @see Query#sortOrder()
-         */
-        @NonNull
-        public CompleteBuilder sortOrder(@Nullable String sortOrder) {
-            this.sortOrder = sortOrder;
-            return this;
-        }
-
-        /**
-         * Builds new instance of {@link Query}.
-         *
-         * @return new instance of {@link Query}.
-         */
-        @NonNull
-        public Query build() {
-            return new Query(
-                    uri,
-                    columns,
-                    where,
-                    whereArgs,
-                    sortOrder
-            );
-        }
-    }
-}
diff --git a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/UpdateQuery.java b/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/UpdateQuery.java
deleted file mode 100644
index f77a18a..0000000
--- a/storio-content-resolver/src/main/java/com/pushtorefresh/storio/contentresolver/query/UpdateQuery.java
+++ /dev/null
@@ -1,217 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.query;
-
-import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import java.util.List;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-import static com.pushtorefresh.storio.internal.Queries.nonNullString;
-import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullList;
-import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullListOfStrings;
-
-/**
- * Update query for {@link com.pushtorefresh.storio.contentresolver.StorIOContentResolver}.
- * <p/>
- * Instances of this class are Immutable.
- */
-public final class UpdateQuery {
-
-    @NonNull
-    private final Uri uri;
-
-    @NonNull
-    private final String where;
-
-    @NonNull
-    private final List<String> whereArgs;
-
-    /**
-     * Please use {@link com.pushtorefresh.storio.contentresolver.query.UpdateQuery.Builder}
-     * instead of constructor.
-     */
-    private UpdateQuery(@NonNull Uri uri, @Nullable String where, @Nullable List<String> whereArgs) {
-        this.uri = uri;
-        this.where = nonNullString(where);
-        this.whereArgs = unmodifiableNonNullList(whereArgs);
-    }
-
-    /**
-     * Gets {@code content://} URI of the insertion request.
-     * <p/>
-     * This can potentially have a record ID if this is an update request for a specific record.
-     *
-     * @return non-null URI of the update request.
-     */
-    @NonNull
-    public Uri uri() {
-        return uri;
-    }
-
-    /**
-     * Gets {@code WHERE} clause.
-     * <p/>
-     * Optional filter declaring which rows to update.
-     * <p/>
-     * Formatted as an SQL {@code WHERE} clause (excluding the {@code WHERE} itself).
-     * <p/>
-     * If empty — Query will update all rows for specified URI.
-     *
-     * @return non-null {@code WHERE} clause.
-     */
-    @NonNull
-    public String where() {
-        return where;
-    }
-
-    /**
-     * Gets optional immutable list of arguments for {@link #where()} clause.
-     *
-     * @return non-null, immutable list of arguments for {@code WHERE} clause.
-     */
-    @NonNull
-    public List<String> whereArgs() {
-        return whereArgs;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        UpdateQuery that = (UpdateQuery) o;
-
-        if (!uri.equals(that.uri)) return false;
-        if (!where.equals(that.where)) return false;
-        return whereArgs.equals(that.whereArgs);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = uri.hashCode();
-        result = 31 * result + where.hashCode();
-        result = 31 * result + whereArgs.hashCode();
-        return result;
-    }
-
-    /**
-     * Creates new builder for {@link UpdateQuery}.
-     *
-     * @return non-null instance of {@link UpdateQuery.Builder}.
-     */
-    @NonNull
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    /**
-     * Builder for {@link UpdateQuery}.
-     */
-    public static final class Builder {
-
-        /**
-         * Please use {@link UpdateQuery#builder()} instead of this.
-         */
-        Builder() {
-        }
-
-        /**
-         * Required: Specifies uri.
-         *
-         * @param uri URI to query.
-         *            This can potentially have a record ID if this is an update
-         *            request for a specific record.
-         * @return builder.
-         * @see UpdateQuery#uri()
-         */
-        @NonNull
-        public CompleteBuilder uri(@NonNull Uri uri) {
-            checkNotNull(uri, "Please specify uri");
-            return new CompleteBuilder(uri);
-        }
-
-        /**
-         * Required: Specifies uri.
-         *
-         * @param uri URI to query.
-         *            This can potentially have a record ID if this is an update
-         *            request for a specific record.
-         * @return builder.
-         * @see UpdateQuery#uri()
-         */
-        @NonNull
-        public CompleteBuilder uri(@NonNull String uri) {
-            checkNotNull(uri, "Uri should not be null");
-            return new CompleteBuilder(Uri.parse(uri));
-        }
-    }
-
-    /**
-     * Compile-time safe part of {@link Builder}.
-     */
-    public static final class CompleteBuilder {
-
-        @NonNull
-        private final Uri uri;
-
-        private String where;
-
-        private List<String> whereArgs;
-
-        CompleteBuilder(@NonNull Uri uri) {
-            this.uri = uri;
-        }
-
-        /**
-         * Optional: Specifies where clause.
-         * <p/>
-         * Default value is {@code null}.
-         *
-         * @param where an optional filter to match rows to update.
-         * @return builder.
-         * @see UpdateQuery#where()
-         */
-        @NonNull
-        public CompleteBuilder where(@Nullable String where) {
-            this.where = where;
-            return this;
-        }
-
-        /**
-         * Optional: Specifies arguments for where clause.
-         * <p/>
-         * Passed objects will be immediately converted to
-         * list {@link String} via calling {@link Object#toString()}.
-         * <p/>
-         * Default value is {@code null}.
-         *
-         * @param whereArgs arguments for {@link UpdateQuery#where}.
-         * @return builder.
-         * @see UpdateQuery#whereArgs()
-         */
-        @NonNull
-        public CompleteBuilder whereArgs(@Nullable Object... whereArgs) {
-            this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
-            return this;
-        }
-
-        /**
-         * Builds new instance of {@link UpdateQuery}.
-         *
-         * @return new instance of {@link UpdateQuery}.
-         */
-        @NonNull
-        public UpdateQuery build() {
-            if (where == null && whereArgs != null && !whereArgs.isEmpty()) {
-                throw new IllegalStateException("You can not use whereArgs without where clause");
-            }
-
-            return new UpdateQuery(
-                    uri,
-                    where,
-                    whereArgs
-            );
-        }
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/ContentResolverTypeMappingTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/ContentResolverTypeMappingTest.java
index bd8d89c..3b7dd9e 100644
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/ContentResolverTypeMappingTest.java
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/ContentResolverTypeMappingTest.java
@@ -1,8 +1,8 @@
 package com.pushtorefresh.storio.contentresolver;
 
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.contentresolver.operation.get.GetResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResolver;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.contentresolver.operations.get.GetResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResolver;
 
 import org.junit.Test;
 
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/ArticleMeta.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/ArticleMeta.java
index 36879db..b49ef10 100644
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/ArticleMeta.java
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/ArticleMeta.java
@@ -6,15 +6,15 @@
 import android.provider.BaseColumns;
 import android.support.annotation.NonNull;
 
-import com.pushtorefresh.storio.contentresolver.operation.delete.DefaultDeleteResolver;
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.contentresolver.operation.get.DefaultGetResolver;
-import com.pushtorefresh.storio.contentresolver.operation.get.GetResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.DefaultPutResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResolver;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-import com.pushtorefresh.storio.contentresolver.query.InsertQuery;
-import com.pushtorefresh.storio.contentresolver.query.UpdateQuery;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DefaultDeleteResolver;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.contentresolver.operations.get.DefaultGetResolver;
+import com.pushtorefresh.storio.contentresolver.operations.get.GetResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.DefaultPutResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResolver;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;
+import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;
 
 import static org.mockito.Mockito.mock;
 
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/DeleteOperationDesignTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/DeleteOperationDesignTest.java
index b32a1fe..895d3dc 100644
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/DeleteOperationDesignTest.java
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/DeleteOperationDesignTest.java
@@ -2,9 +2,9 @@
 
 import android.net.Uri;
 
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResult;
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResults;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResult;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResults;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
 
 import org.junit.Test;
 
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/DesignTestStorIOContentResolver.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/DesignTestStorIOContentResolver.java
index 960a067..c235754 100644
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/DesignTestStorIOContentResolver.java
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/DesignTestStorIOContentResolver.java
@@ -9,10 +9,10 @@
 import com.pushtorefresh.storio.contentresolver.Changes;
 import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
 import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-import com.pushtorefresh.storio.contentresolver.query.InsertQuery;
-import com.pushtorefresh.storio.contentresolver.query.Query;
-import com.pushtorefresh.storio.contentresolver.query.UpdateQuery;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
+import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;
 
 import java.util.Set;
 
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/GetOperationDesignTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/GetOperationDesignTest.java
index 4e0a10a..9e88f06 100644
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/GetOperationDesignTest.java
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/GetOperationDesignTest.java
@@ -3,8 +3,8 @@
 import android.database.Cursor;
 import android.net.Uri;
 
-import com.pushtorefresh.storio.contentresolver.operation.get.GetResolver;
-import com.pushtorefresh.storio.contentresolver.query.Query;
+import com.pushtorefresh.storio.contentresolver.operations.get.GetResolver;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
 
 import org.junit.Test;
 
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/PutOperationDesignTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/PutOperationDesignTest.java
index 3c28478..94af0f2 100644
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/PutOperationDesignTest.java
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/design/PutOperationDesignTest.java
@@ -4,12 +4,12 @@
 import android.net.Uri;
 import android.support.annotation.NonNull;
 
-import com.pushtorefresh.storio.contentresolver.operation.put.DefaultPutResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResult;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResults;
-import com.pushtorefresh.storio.contentresolver.query.InsertQuery;
-import com.pushtorefresh.storio.contentresolver.query.UpdateQuery;
+import com.pushtorefresh.storio.contentresolver.operations.put.DefaultPutResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResult;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResults;
+import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;
+import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;
 
 import org.junit.Test;
 
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/impl/DefaultStorIOContentResolverTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/impl/DefaultStorIOContentResolverTest.java
index 24ca722..9881923 100644
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/impl/DefaultStorIOContentResolverTest.java
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/impl/DefaultStorIOContentResolverTest.java
@@ -4,9 +4,9 @@
 
 import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
 import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.contentresolver.operation.get.GetResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResolver;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.contentresolver.operations.get.GetResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResolver;
 
 import org.junit.Test;
 
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DefaultDeleteResolverTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DefaultDeleteResolverTest.java
deleted file mode 100644
index 6563fe9..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DefaultDeleteResolverTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import android.net.Uri;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class DefaultDeleteResolverTest {
-
-    @Test
-    public void performDelete() {
-        final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
-        final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
-
-        when(storIOContentResolver.internal())
-                .thenReturn(internal);
-
-        final int expectedNumberOfRowsDeleted = 1;
-
-        when(internal.delete(any(DeleteQuery.class)))
-                .thenReturn(expectedNumberOfRowsDeleted);
-
-        final Uri expectedUri = mock(Uri.class);
-
-        final DeleteQuery expectedDeleteQuery = DeleteQuery.builder()
-                .uri(expectedUri)
-                .where("test where clause")
-                .whereArgs("test")
-                .build();
-
-        final TestItem testItem = TestItem.newInstance();
-
-        final DefaultDeleteResolver<TestItem> defaultDeleteResolver = new DefaultDeleteResolver<TestItem>() {
-            @NonNull
-            @Override
-            protected DeleteQuery mapToDeleteQuery(@NonNull TestItem object) {
-                assertSame(testItem, object);
-                return expectedDeleteQuery;
-            }
-        };
-
-        // Performing Delete Operation
-        final DeleteResult deleteResult = defaultDeleteResolver.performDelete(storIOContentResolver, testItem);
-
-        // checks that required delete was performed
-        verify(internal, times(1)).delete(expectedDeleteQuery);
-
-        // only one delete should be performed
-        verify(internal, times(1)).delete(any(DeleteQuery.class));
-
-        // delete result checks
-        assertEquals(expectedNumberOfRowsDeleted, deleteResult.numberOfRowsDeleted());
-        assertEquals(1, deleteResult.affectedUris().size());
-        assertTrue(deleteResult.affectedUris().contains(expectedUri));
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteByQueryStub.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteByQueryStub.java
deleted file mode 100644
index fcd3396..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteByQueryStub.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import android.net.Uri;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
-
-import rx.Observable;
-import rx.functions.Action1;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-// stub class to avoid violation of DRY in tests
-class DeleteByQueryStub {
-
-    @NonNull
-    final StorIOContentResolver storIOContentResolver;
-
-    @NonNull
-    private final StorIOContentResolver.Internal internal;
-
-    @NonNull
-    final DeleteQuery deleteQuery;
-
-    @NonNull
-    final DeleteResolver<DeleteQuery> deleteResolver;
-
-    @NonNull
-    private final DeleteResult deleteResult;
-
-    @SuppressWarnings("unchecked")
-    private DeleteByQueryStub() {
-        storIOContentResolver = mock(StorIOContentResolver.class);
-        internal = mock(StorIOContentResolver.Internal.class);
-
-        when(storIOContentResolver.internal())
-                .thenReturn(internal);
-
-        when(storIOContentResolver.delete())
-                .thenReturn(new PreparedDelete.Builder(storIOContentResolver));
-
-        deleteQuery = DeleteQuery.builder()
-                .uri(mock(Uri.class))
-                .build();
-
-        deleteResolver = mock(DeleteResolver.class);
-
-        deleteResult = DeleteResult.newInstance(1, deleteQuery.uri());
-
-        when(deleteResolver.performDelete(storIOContentResolver, deleteQuery))
-                .thenReturn(deleteResult);
-    }
-
-    @NonNull
-    static DeleteByQueryStub newInstance() {
-        return new DeleteByQueryStub();
-    }
-
-    void verifyBehavior(@NonNull DeleteResult actualDeleteResult) {
-        // checks that required delete was performed
-        verify(deleteResolver, times(1)).performDelete(storIOContentResolver, deleteQuery);
-
-        // only one call to DeleteResolver.performDelete() should occur
-        verify(deleteResolver, times(1)).performDelete(any(StorIOContentResolver.class), any(DeleteQuery.class));
-
-        // checks that actual delete result equals to expected
-        assertEquals(deleteResult, actualDeleteResult);
-    }
-
-    void verifyBehavior(@NonNull Observable<DeleteResult> deleteResultObservable) {
-        new ObservableBehaviorChecker<DeleteResult>()
-                .observable(deleteResultObservable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<DeleteResult>() {
-                    @Override
-                    public void call(DeleteResult deleteResult) {
-                        verifyBehavior(deleteResult);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteObjectsStub.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteObjectsStub.java
deleted file mode 100644
index 026e165..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteObjectsStub.java
+++ /dev/null
@@ -1,171 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import android.net.Uri;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import rx.Observable;
-import rx.functions.Action1;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-// stub class to avoid violation of DRY in tests
-class DeleteObjectsStub {
-
-    @NonNull
-    final StorIOContentResolver storIOContentResolver;
-
-    @NonNull
-    private final StorIOContentResolver.Internal internal;
-
-    @NonNull
-    final List<TestItem> items;
-
-    @NonNull
-    final DeleteResolver<TestItem> deleteResolver;
-
-    @NonNull
-    private final ContentResolverTypeMapping<TestItem> typeMapping;
-
-    @NonNull
-    private final Map<TestItem, DeleteResult> testItemToDeleteResultMap;
-
-    private final boolean withTypeMapping;
-
-    @SuppressWarnings("unchecked")
-    private DeleteObjectsStub(boolean withTypeMapping, int numberOfTestItems) {
-        this.withTypeMapping = withTypeMapping;
-
-        storIOContentResolver = mock(StorIOContentResolver.class);
-        internal = mock(StorIOContentResolver.Internal.class);
-
-        when(storIOContentResolver.internal())
-                .thenReturn(internal);
-
-        when(storIOContentResolver.delete())
-                .thenReturn(new PreparedDelete.Builder(storIOContentResolver));
-
-        deleteResolver = mock(DeleteResolver.class);
-
-        items = new ArrayList<TestItem>(numberOfTestItems);
-        testItemToDeleteResultMap = new HashMap<TestItem, DeleteResult>(numberOfTestItems);
-
-        typeMapping = mock(ContentResolverTypeMapping.class);
-
-        if (withTypeMapping) {
-            when(typeMapping.deleteResolver()).thenReturn(deleteResolver);
-            when(internal.typeMapping(TestItem.class)).thenReturn(typeMapping);
-        }
-
-        for (int i = 0; i < numberOfTestItems; i++) {
-            final TestItem testItem = TestItem.newInstance();
-            items.add(testItem);
-
-            final Uri testItemUri = mock(Uri.class);
-
-            final DeleteResult deleteResult = DeleteResult.newInstance(1, testItemUri);
-            testItemToDeleteResultMap.put(testItem, deleteResult);
-
-            when(deleteResolver.performDelete(storIOContentResolver, testItem))
-                    .thenReturn(deleteResult);
-        }
-    }
-
-    @NonNull
-    static DeleteObjectsStub newInstanceForDeleteMultipleObjectsWithoutTypeMapping() {
-        return new DeleteObjectsStub(false, 3);
-    }
-
-    @NonNull
-    static DeleteObjectsStub newInstanceForDeleteMultipleObjectsWithTypeMapping() {
-        return new DeleteObjectsStub(true, 3);
-    }
-
-    @NonNull
-    static DeleteObjectsStub newInstanceForDeleteOneObjectWithoutTypeMapping() {
-        return new DeleteObjectsStub(false, 1);
-    }
-
-    @NonNull
-    static DeleteObjectsStub newInstanceForDeleteOneObjectWithTypeMapping() {
-        return new DeleteObjectsStub(true, 1);
-    }
-
-    void verifyBehaviorForDeleteMultipleObjects(@NonNull DeleteResults<TestItem> deleteResults) {
-        verify(storIOContentResolver).delete();
-
-        if (withTypeMapping || items.size() > 1) {
-            // should be called only once because of Performance!
-            verify(storIOContentResolver).internal();
-        }
-
-        // checks that delete was performed same amount of times as count of items
-        verify(deleteResolver, times(items.size())).performDelete(eq(storIOContentResolver), any(TestItem.class));
-
-        for (final TestItem testItem : items) {
-            // checks that delete was performed for each item
-            verify(deleteResolver, times(1)).performDelete(storIOContentResolver, testItem);
-
-            final DeleteResult expectedDeleteResult = testItemToDeleteResultMap.get(testItem);
-
-            // checks that delete results contains result of deletion of each item
-            assertEquals(expectedDeleteResult, deleteResults.results().get(testItem));
-        }
-
-        assertEquals(items.size(), deleteResults.results().size());
-
-        if (withTypeMapping) {
-            verify(internal, times(items.size())).typeMapping(TestItem.class);
-            verify(typeMapping, times(items.size())).deleteResolver();
-        }
-
-        verifyNoMoreInteractions(storIOContentResolver, internal, typeMapping, deleteResolver);
-    }
-
-    void verifyBehaviorForDeleteMultipleObjects(@NonNull Observable<DeleteResults<TestItem>> deleteResultsObservable) {
-        new ObservableBehaviorChecker<DeleteResults<TestItem>>()
-                .observable(deleteResultsObservable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<DeleteResults<TestItem>>() {
-                    @Override
-                    public void call(DeleteResults<TestItem> deleteResults) {
-                        verifyBehaviorForDeleteMultipleObjects(deleteResults);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-
-    void verifyBehaviorForDeleteOneObject(@NonNull DeleteResult deleteResult) {
-        Map<TestItem, DeleteResult> deleteResultsMap = new HashMap<TestItem, DeleteResult>(1);
-        deleteResultsMap.put(items.get(0), deleteResult);
-        verifyBehaviorForDeleteMultipleObjects(DeleteResults.newInstance(deleteResultsMap));
-    }
-
-    void verifyBehaviorForDeleteOneObject(@NonNull Observable<DeleteResult> deleteResultObservable) {
-        new ObservableBehaviorChecker<DeleteResult>()
-                .observable(deleteResultObservable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<DeleteResult>() {
-                    @Override
-                    public void call(DeleteResult deleteResult) {
-                        verifyBehaviorForDeleteOneObject(deleteResult);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResultTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResultTest.java
deleted file mode 100644
index 49013e8..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResultTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import android.net.Uri;
-
-import org.junit.Test;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-public class DeleteResultTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void nullAffectedUri() {
-        DeleteResult.newInstance(1, (Uri) null);
-    }
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void nullAffectedUris() {
-        DeleteResult.newInstance(1, (Set<Uri>) null);
-    }
-
-    @Test
-    public void numberOfRowsDeleted() {
-        final DeleteResult deleteResult = DeleteResult.newInstance(3, mock(Uri.class));
-        assertEquals(3, deleteResult.numberOfRowsDeleted());
-    }
-
-    @Test
-    public void affectedUri() {
-        final Uri affectedUri = mock(Uri.class);
-        final DeleteResult deleteResult = DeleteResult.newInstance(2, affectedUri);
-        assertEquals(1, deleteResult.affectedUris().size());
-        assertTrue(deleteResult.affectedUris().contains(affectedUri));
-    }
-
-    @Test
-    public void affectedUris() {
-        final Set<Uri> affectedUris = new HashSet<Uri>();
-
-        affectedUris.add(mock(Uri.class));
-        affectedUris.add(mock(Uri.class));
-        affectedUris.add(mock(Uri.class));
-
-        final DeleteResult deleteResult = DeleteResult.newInstance(3, affectedUris);
-        assertEquals(affectedUris, deleteResult.affectedUris());
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResultsTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResultsTest.java
deleted file mode 100644
index af25150..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/DeleteResultsTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import android.net.Uri;
-
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-
-public class DeleteResultsTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void nullResults() {
-        DeleteResults.newInstance(null);
-    }
-
-    @Test
-    public void results() {
-        final Map<String, DeleteResult> results = new HashMap<String, DeleteResult>();
-        results.put("testString", DeleteResult.newInstance(1, mock(Uri.class)));
-        results.put("testString", DeleteResult.newInstance(1, mock(Uri.class)));
-
-        final DeleteResults<String> deleteResults = DeleteResults.newInstance(results);
-
-        assertEquals(results, deleteResults.results());
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteByQueryTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteByQueryTest.java
deleted file mode 100644
index 43b4e30..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteByQueryTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import org.junit.Test;
-
-import rx.Observable;
-
-public class PreparedDeleteByQueryTest {
-
-    @Test
-    public void shouldDeleteByQueryBlocking() {
-        final DeleteByQueryStub deleteStub = DeleteByQueryStub.newInstance();
-
-        final DeleteResult deleteResult = deleteStub.storIOContentResolver
-                .delete()
-                .byQuery(deleteStub.deleteQuery)
-                .withDeleteResolver(deleteStub.deleteResolver)
-                .prepare()
-                .executeAsBlocking();
-
-        deleteStub.verifyBehavior(deleteResult);
-    }
-
-    @Test
-    public void shouldDeleteByQueryAsObservable() {
-        final DeleteByQueryStub deleteStub = DeleteByQueryStub.newInstance();
-
-        final Observable<DeleteResult> deleteResultObservable = deleteStub.storIOContentResolver
-                .delete()
-                .byQuery(deleteStub.deleteQuery)
-                .withDeleteResolver(deleteStub.deleteResolver)
-                .prepare()
-                .createObservable();
-
-        deleteStub.verifyBehavior(deleteResultObservable);
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteCollectionOfObjectsTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteCollectionOfObjectsTest.java
deleted file mode 100644
index 2da1469..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteCollectionOfObjectsTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-
-import org.junit.Test;
-import org.junit.experimental.runners.Enclosed;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-import rx.Observable;
-import rx.observers.TestSubscriber;
-
-import static java.util.Arrays.asList;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(Enclosed.class)
-public class PreparedDeleteCollectionOfObjectsTest {
-
-    public static class WithoutTypeMapping {
-
-        @Test
-        public void shouldDeleteObjectsWithoutTypeMappingBlocking() {
-            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteMultipleObjectsWithoutTypeMapping();
-
-            final DeleteResults<TestItem> deleteResults = deleteStub.storIOContentResolver
-                    .delete()
-                    .objects(deleteStub.items)
-                    .withDeleteResolver(deleteStub.deleteResolver)
-                    .prepare()
-                    .executeAsBlocking();
-
-            deleteStub.verifyBehaviorForDeleteMultipleObjects(deleteResults);
-        }
-
-        @Test
-        public void shouldDeleteObjectsWithoutTypeMappingAsObservable() {
-            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteMultipleObjectsWithoutTypeMapping();
-
-            final Observable<DeleteResults<TestItem>> observable = deleteStub.storIOContentResolver
-                    .delete()
-                    .objects(deleteStub.items)
-                    .withDeleteResolver(deleteStub.deleteResolver)
-                    .prepare()
-                    .createObservable();
-
-            deleteStub.verifyBehaviorForDeleteMultipleObjects(observable);
-        }
-    }
-
-    public static class WithTypeMapping {
-
-        @Test
-        public void shouldDeleteObjectsWithTypeMappingBlocking() {
-            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteMultipleObjectsWithTypeMapping();
-
-            final DeleteResults<TestItem> deleteResults = deleteStub.storIOContentResolver
-                    .delete()
-                    .objects(deleteStub.items)
-                    .prepare()
-                    .executeAsBlocking();
-
-            deleteStub.verifyBehaviorForDeleteMultipleObjects(deleteResults);
-        }
-
-        @Test
-        public void shouldDeleteObjectsWithTypeMappingAsObservable() {
-            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteMultipleObjectsWithTypeMapping();
-
-            final Observable<DeleteResults<TestItem>> observable = deleteStub.storIOContentResolver
-                    .delete()
-                    .objects(deleteStub.items)
-                    .prepare()
-                    .createObservable();
-
-            deleteStub.verifyBehaviorForDeleteMultipleObjects(observable);
-        }
-    }
-
-    public static class NoTypeMappingError {
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderBlocking() {
-            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
-            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
-
-            when(storIOContentResolver.internal()).thenReturn(internal);
-
-            when(storIOContentResolver.delete()).thenReturn(new PreparedDelete.Builder(storIOContentResolver));
-
-            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
-
-            final PreparedDelete<DeleteResults<TestItem>> preparedDelete = storIOContentResolver
-                    .delete()
-                    .objects(items)
-                    .prepare();
-
-            try {
-                preparedDelete.executeAsBlocking();
-                fail();
-            } catch (IllegalStateException expected) {
-                // it's okay, no type mapping was found
-            }
-
-            verify(storIOContentResolver).delete();
-            verify(storIOContentResolver).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).delete(any(DeleteQuery.class));
-            verifyNoMoreInteractions(storIOContentResolver, internal);
-        }
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderAsObservable() {
-            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
-            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
-
-            when(storIOContentResolver.internal()).thenReturn(internal);
-
-            when(storIOContentResolver.delete()).thenReturn(new PreparedDelete.Builder(storIOContentResolver));
-
-            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
-
-            final TestSubscriber<DeleteResults<TestItem>> testSubscriber = new TestSubscriber<DeleteResults<TestItem>>();
-
-            storIOContentResolver
-                    .delete()
-                    .objects(items)
-                    .prepare()
-                    .createObservable()
-                    .subscribe(testSubscriber);
-
-            testSubscriber.awaitTerminalEvent();
-            testSubscriber.assertNoValues();
-            testSubscriber.assertError(IllegalStateException.class);
-
-            verify(storIOContentResolver).delete();
-            verify(storIOContentResolver).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).delete(any(DeleteQuery.class));
-            verifyNoMoreInteractions(storIOContentResolver, internal);
-        }
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteObjectTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteObjectTest.java
deleted file mode 100644
index cd380be..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/PreparedDeleteObjectTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-
-import org.junit.Test;
-import org.junit.experimental.runners.Enclosed;
-import org.junit.runner.RunWith;
-
-import rx.Observable;
-import rx.observers.TestSubscriber;
-
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(Enclosed.class)
-public class PreparedDeleteObjectTest {
-
-    public static class WithoutTypeMapping {
-
-        @Test
-        public void shouldDeleteObjectWithoutTypeMappingBlocking() {
-            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteOneObjectWithoutTypeMapping();
-
-            final DeleteResult deleteResult = deleteStub.storIOContentResolver
-                    .delete()
-                    .object(deleteStub.items.get(0))
-                    .withDeleteResolver(deleteStub.deleteResolver)
-                    .prepare()
-                    .executeAsBlocking();
-
-            deleteStub.verifyBehaviorForDeleteOneObject(deleteResult);
-        }
-
-        @Test
-        public void shouldDeleteObjectWithoutTypeMappingAsObservable() {
-            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteOneObjectWithoutTypeMapping();
-
-            final Observable<DeleteResult> observable = deleteStub.storIOContentResolver
-                    .delete()
-                    .object(deleteStub.items.get(0))
-                    .withDeleteResolver(deleteStub.deleteResolver)
-                    .prepare()
-                    .createObservable();
-
-            deleteStub.verifyBehaviorForDeleteOneObject(observable);
-        }
-    }
-
-    public static class WithTypeMapping {
-
-        @Test
-        public void shouldDeleteObjectWithTypeMappingBlocking() {
-            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteOneObjectWithTypeMapping();
-
-            final DeleteResult deleteResult = deleteStub.storIOContentResolver
-                    .delete()
-                    .object(deleteStub.items.get(0))
-                    .prepare()
-                    .executeAsBlocking();
-
-            deleteStub.verifyBehaviorForDeleteOneObject(deleteResult);
-        }
-
-        @Test
-        public void shouldDeleteObjectWithTypeMappingAsObservable() {
-            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteOneObjectWithTypeMapping();
-
-            final Observable<DeleteResult> observable = deleteStub.storIOContentResolver
-                    .delete()
-                    .object(deleteStub.items.get(0))
-                    .prepare()
-                    .createObservable();
-
-            deleteStub.verifyBehaviorForDeleteOneObject(observable);
-        }
-    }
-
-    public static class NoTypeMappingError {
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderBlocking() {
-            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
-            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
-
-            when(storIOContentResolver.internal()).thenReturn(internal);
-
-            when(storIOContentResolver.delete()).thenReturn(new PreparedDelete.Builder(storIOContentResolver));
-
-            final PreparedDelete<DeleteResult> preparedDelete = storIOContentResolver
-                    .delete()
-                    .object(TestItem.newInstance())
-                    .prepare();
-
-            try {
-                preparedDelete.executeAsBlocking();
-                fail();
-            } catch (IllegalStateException expected) {
-                // it's okay, no type mapping was found
-            }
-
-            verify(storIOContentResolver).delete();
-            verify(storIOContentResolver).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).delete(any(DeleteQuery.class));
-            verifyNoMoreInteractions(storIOContentResolver, internal);
-        }
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderAsObservable() {
-            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
-            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
-
-            when(storIOContentResolver.internal()).thenReturn(internal);
-
-            when(storIOContentResolver.delete()).thenReturn(new PreparedDelete.Builder(storIOContentResolver));
-
-            final TestSubscriber<DeleteResult> testSubscriber = new TestSubscriber<DeleteResult>();
-
-            storIOContentResolver
-                    .delete()
-                    .object(TestItem.newInstance())
-                    .prepare()
-                    .createObservable()
-                    .subscribe(testSubscriber);
-
-            testSubscriber.awaitTerminalEvent();
-            testSubscriber.assertNoValues();
-            testSubscriber.assertError(IllegalStateException.class);
-
-            verify(storIOContentResolver).delete();
-            verify(storIOContentResolver).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).delete(any(DeleteQuery.class));
-            verifyNoMoreInteractions(storIOContentResolver, internal);
-        }
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/TestItem.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/TestItem.java
deleted file mode 100644
index 5effc9d..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/delete/TestItem.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.delete;
-
-import android.support.annotation.NonNull;
-
-class TestItem {
-
-    private TestItem() {
-
-    }
-
-    @NonNull
-    public static TestItem newInstance() {
-        return new TestItem();
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/DefaultGetResolverTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/DefaultGetResolverTest.java
deleted file mode 100644
index 821ff79..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/DefaultGetResolverTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.get;
-
-import android.database.Cursor;
-import android.net.Uri;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.Query;
-
-import org.junit.Test;
-
-import static junit.framework.Assert.assertSame;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class DefaultGetResolverTest {
-
-    @Test
-    public void query() {
-        final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
-        final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
-
-        final Query query = Query.builder()
-                .uri(mock(Uri.class))
-                .build();
-
-        final Cursor expectedCursor = mock(Cursor.class);
-
-        when(storIOContentResolver.internal())
-                .thenReturn(internal);
-
-        when(internal.query(query))
-                .thenReturn(expectedCursor);
-
-        final GetResolver<TestItem> defaultGetResolver = new DefaultGetResolver<TestItem>() {
-            @NonNull
-            @Override
-            public TestItem mapFromCursor(@NonNull Cursor cursor) {
-                assertSame(expectedCursor, cursor);
-                return new TestItem();
-            }
-        };
-
-        final Cursor actualCursor = defaultGetResolver.performGet(storIOContentResolver, query);
-
-        // only one request should occur
-        verify(internal, times(1)).query(any(Query.class));
-
-        // and this request should be equals to original
-        verify(internal, times(1)).query(query);
-
-        assertSame(expectedCursor, actualCursor);
-    }
-
-    private static class TestItem {
-
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/GetCursorStub.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/GetCursorStub.java
deleted file mode 100644
index a393d3f..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/GetCursorStub.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.get;
-
-import android.database.Cursor;
-import android.net.Uri;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.Changes;
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.Query;
-import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
-
-import rx.Observable;
-import rx.functions.Action1;
-
-import static junit.framework.Assert.assertSame;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-class GetCursorStub {
-
-    @NonNull
-    final StorIOContentResolver storIOContentResolver;
-
-    @NonNull
-    private final StorIOContentResolver.Internal internal;
-
-    @NonNull
-    final Query query;
-
-    @NonNull
-    final GetResolver<Cursor> getResolver;
-
-    @NonNull
-    final Cursor cursor;
-
-    @SuppressWarnings("unchecked")
-    private GetCursorStub() {
-        storIOContentResolver = mock(StorIOContentResolver.class);
-        internal = mock(StorIOContentResolver.Internal.class);
-
-        query = Query.builder()
-                .uri(mock(Uri.class))
-                .build();
-
-        getResolver = mock(GetResolver.class);
-        cursor = mock(Cursor.class);
-
-        when(storIOContentResolver.internal())
-                .thenReturn(internal);
-
-        when(storIOContentResolver.get())
-                .thenReturn(new PreparedGet.Builder(storIOContentResolver));
-
-        when(getResolver.performGet(storIOContentResolver, query))
-                .thenReturn(cursor);
-
-        when(storIOContentResolver.observeChangesOfUri(query.uri()))
-                .thenReturn(Observable.<Changes>empty());
-
-        when(getResolver.mapFromCursor(cursor))
-                .thenReturn(cursor);
-    }
-
-    @NonNull
-    static GetCursorStub newInstance() {
-        return new GetCursorStub();
-    }
-
-    void verifyQueryBehaviorForCursor(@NonNull Cursor actualCursor) {
-        verify(storIOContentResolver, times(1)).get();
-        verify(getResolver, times(1)).performGet(storIOContentResolver, query);
-        assertSame(cursor, actualCursor);
-        verify(cursor, times(0)).close();
-        verifyNoMoreInteractions(storIOContentResolver, internal, getResolver, cursor);
-    }
-
-    void verifyQueryBehaviorForCursor(@NonNull Observable<Cursor> observable) {
-        new ObservableBehaviorChecker<Cursor>()
-                .observable(observable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<Cursor>() {
-                    @Override
-                    public void call(Cursor cursor) {
-                        // Get Operation should be subscribed to changes of Uri
-                        verify(storIOContentResolver).observeChangesOfUri(query.uri());
-
-                        verifyQueryBehaviorForCursor(cursor);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/GetObjectsStub.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/GetObjectsStub.java
deleted file mode 100644
index 73561b2..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/GetObjectsStub.java
+++ /dev/null
@@ -1,187 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.get;
-
-import android.database.Cursor;
-import android.net.Uri;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.Changes;
-import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.Query;
-import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
-
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import rx.Observable;
-import rx.functions.Action1;
-
-import static com.pushtorefresh.storio.test.Asserts.assertThatListIsImmutable;
-import static junit.framework.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-class GetObjectsStub {
-
-    @NonNull
-    final StorIOContentResolver storIOContentResolver;
-
-    @NonNull
-    private final StorIOContentResolver.Internal internal;
-
-    @NonNull
-    final Query query;
-
-    @NonNull
-    final List<TestItem> items;
-
-    @NonNull
-    final GetResolver<TestItem> getResolver;
-
-    @NonNull
-    final Cursor cursor;
-
-    @NonNull
-    private final ContentResolverTypeMapping<TestItem> typeMapping;
-
-    private final boolean withTypeMapping;
-
-    @SuppressWarnings("unchecked")
-    private GetObjectsStub(boolean withTypeMapping) {
-        this.withTypeMapping = withTypeMapping;
-
-        storIOContentResolver = mock(StorIOContentResolver.class);
-        internal = mock(StorIOContentResolver.Internal.class);
-
-        query = Query.builder()
-                .uri(mock(Uri.class))
-                .build();
-
-        getResolver = mock(GetResolver.class);
-        cursor = mock(Cursor.class);
-
-        items = new ArrayList<TestItem>();
-        items.add(new TestItem());
-        items.add(new TestItem());
-        items.add(new TestItem());
-
-        when(storIOContentResolver.internal())
-                .thenReturn(internal);
-
-        when(cursor.moveToNext())
-                .thenAnswer(new Answer<Boolean>() {
-                    int invocationsCount = 0;
-
-                    @Override
-                    public Boolean answer(InvocationOnMock invocation) throws Throwable {
-                        return invocationsCount++ < items.size();
-                    }
-                });
-
-        when(cursor.getCount())
-                .thenReturn(items.size());
-
-        when(storIOContentResolver.get())
-                .thenReturn(new PreparedGet.Builder(storIOContentResolver));
-
-        when(getResolver.performGet(storIOContentResolver, query))
-                .thenReturn(cursor);
-
-        when(storIOContentResolver.observeChangesOfUri(query.uri()))
-                .thenReturn(Observable.<Changes>empty());
-
-        when(getResolver.mapFromCursor(cursor))
-                .thenAnswer(new Answer<TestItem>() {
-                    int invocationsCount = 0;
-
-                    @Override
-                    public TestItem answer(InvocationOnMock invocation) throws Throwable {
-                        final TestItem testItem = items.get(invocationsCount);
-                        invocationsCount++;
-                        return testItem;
-                    }
-                });
-
-        typeMapping = mock(ContentResolverTypeMapping.class);
-
-        if (withTypeMapping) {
-            when(internal.typeMapping(TestItem.class)).thenReturn(typeMapping);
-            when(typeMapping.getResolver()).thenReturn(getResolver);
-        }
-    }
-
-    @NonNull
-    static GetObjectsStub newStubWithoutTypeMapping() {
-        return new GetObjectsStub(false);
-    }
-
-    @NonNull
-    static GetObjectsStub newStubWithTypeMapping() {
-        return new GetObjectsStub(true);
-    }
-
-    void verifyBehavior(@NonNull List<TestItem> actualList) {
-        // should be called once
-        verify(storIOContentResolver).get();
-
-        // should be called once
-        verify(getResolver).performGet(storIOContentResolver, query);
-
-        // should be called only once because of Performance!
-        verify(cursor).getCount();
-
-        // should be called same number of times as count of items in cursor + 1 (last -> false)
-        verify(cursor, times(items.size() + 1)).moveToNext();
-
-        // should be called same number of times as count of items in cursor
-        verify(getResolver, times(items.size())).mapFromCursor(cursor);
-
-        // cursor should be closed!
-        verify(cursor).close();
-
-        // checks that items are okay
-        assertEquals(items, actualList);
-
-        // returned list should be immutable
-        assertThatListIsImmutable(actualList);
-
-        if (withTypeMapping) {
-            // should be called only once because of Performance!
-            verify(storIOContentResolver).internal();
-
-            // should be called only once because of Performance!
-            verify(internal).typeMapping(TestItem.class);
-
-            // should be called only once
-            verify(typeMapping).getResolver();
-        }
-
-        verifyNoMoreInteractions(storIOContentResolver, internal, getResolver, cursor);
-    }
-
-    void verifyBehavior(@NonNull Observable<List<TestItem>> observable) {
-        when(storIOContentResolver.observeChangesOfUri(query.uri()))
-                .thenReturn(Observable.<Changes>empty());
-
-        new ObservableBehaviorChecker<List<TestItem>>()
-                .observable(observable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<List<TestItem>>() {
-                    @Override
-                    public void call(List<TestItem> testItems) {
-                        // Get Operation should be subscribed to changes of Uri!
-                        verify(storIOContentResolver).observeChangesOfUri(query.uri());
-
-                        verifyBehavior(testItems);
-                    }
-                })
-                .checkBehaviorOfObservable();
-
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetCursorTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetCursorTest.java
deleted file mode 100644
index 7058df5..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetCursorTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.get;
-
-import android.database.Cursor;
-
-import org.junit.Test;
-
-import rx.Observable;
-
-public class PreparedGetCursorTest {
-
-    @Test
-    public void getCursorBlocking() {
-        final GetCursorStub getStub = GetCursorStub.newInstance();
-
-        final Cursor cursor = getStub.storIOContentResolver
-                .get()
-                .cursor()
-                .withQuery(getStub.query)
-                .withGetResolver(getStub.getResolver)
-                .prepare()
-                .executeAsBlocking();
-
-        getStub.verifyQueryBehaviorForCursor(cursor);
-    }
-
-
-    @Test
-    public void getCursorObservable() {
-        final GetCursorStub getStub = GetCursorStub.newInstance();
-
-        final Observable<Cursor> cursorObservable = getStub.storIOContentResolver
-                .get()
-                .cursor()
-                .withQuery(getStub.query)
-                .withGetResolver(getStub.getResolver)
-                .prepare()
-                .createObservable()
-                .take(1);
-
-        getStub.verifyQueryBehaviorForCursor(cursorObservable);
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetListOfObjectsTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetListOfObjectsTest.java
deleted file mode 100644
index befd225..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/PreparedGetListOfObjectsTest.java
+++ /dev/null
@@ -1,161 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.get;
-
-import android.net.Uri;
-
-import com.pushtorefresh.storio.contentresolver.Changes;
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.Query;
-
-import org.junit.Test;
-import org.junit.experimental.runners.Enclosed;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-import rx.Observable;
-import rx.observers.TestSubscriber;
-
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(Enclosed.class)
-public class PreparedGetListOfObjectsTest {
-
-    public static class WithoutTypeMapping {
-
-        @Test
-        public void shouldGetListOfObjectsWithoutTypeMappingBlocking() {
-            final GetObjectsStub getStub = GetObjectsStub.newStubWithoutTypeMapping();
-
-            final List<TestItem> testItems = getStub.storIOContentResolver
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(getStub.query)
-                    .withGetResolver(getStub.getResolver)
-                    .prepare()
-                    .executeAsBlocking();
-
-            getStub.verifyBehavior(testItems);
-        }
-
-        @Test
-        public void shouldGetListOfObjectsWithoutTypeMappingAsObservable() {
-            final GetObjectsStub getStub = GetObjectsStub.newStubWithoutTypeMapping();
-
-            final Observable<List<TestItem>> testItemsObservable = getStub.storIOContentResolver
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(getStub.query)
-                    .withGetResolver(getStub.getResolver)
-                    .prepare()
-                    .createObservable()
-                    .take(1);
-
-            getStub.verifyBehavior(testItemsObservable);
-        }
-    }
-
-    public static class WithTypeMapping {
-
-        @Test
-        public void shouldGetListOfObjectsWithTypeMappingBlocking() {
-            final GetObjectsStub getStub = GetObjectsStub.newStubWithTypeMapping();
-
-            final List<TestItem> testItems = getStub.storIOContentResolver
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(getStub.query)
-                    .prepare()
-                    .executeAsBlocking();
-
-            getStub.verifyBehavior(testItems);
-        }
-
-        @Test
-        public void shouldGetListOfObjectsWithTypeMappingAsObservable() {
-            final GetObjectsStub getStub = GetObjectsStub.newStubWithTypeMapping();
-
-            final Observable<List<TestItem>> testItemsObservable = getStub.storIOContentResolver
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(getStub.query)
-                    .prepare()
-                    .createObservable()
-                    .take(1);
-
-            getStub.verifyBehavior(testItemsObservable);
-        }
-    }
-
-    public static class NoTypeMappingError {
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAccessingContentProviderBlocking() {
-            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
-            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
-
-            when(storIOContentResolver.internal()).thenReturn(internal);
-
-            when(storIOContentResolver.get()).thenReturn(new PreparedGet.Builder(storIOContentResolver));
-
-            final PreparedGet<List<TestItem>> preparedGet = storIOContentResolver
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(mock(Query.class))
-                    .prepare();
-
-            try {
-                preparedGet.executeAsBlocking();
-                fail();
-            } catch (IllegalStateException expected) {
-                // it's okay, no type mapping was found
-            }
-
-            verify(storIOContentResolver).get();
-            verify(storIOContentResolver).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).query(any(Query.class));
-            verifyNoMoreInteractions(storIOContentResolver, internal);
-        }
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAccessingContentProviderAsObservable() {
-            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
-            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
-
-            when(storIOContentResolver.internal()).thenReturn(internal);
-
-            when(storIOContentResolver.get()).thenReturn(new PreparedGet.Builder(storIOContentResolver));
-
-            when(storIOContentResolver.observeChangesOfUri(any(Uri.class)))
-                    .thenReturn(Observable.<Changes>empty());
-
-            final TestSubscriber<List<TestItem>> testSubscriber = new TestSubscriber<List<TestItem>>();
-
-            storIOContentResolver
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(mock(Query.class))
-                    .prepare()
-                    .createObservable()
-                    .subscribe(testSubscriber);
-
-            testSubscriber.awaitTerminalEvent();
-            testSubscriber.assertNoValues();
-            testSubscriber.assertError(IllegalStateException.class);
-
-            verify(storIOContentResolver).get();
-            verify(storIOContentResolver).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).query(any(Query.class));
-            verify(storIOContentResolver).observeChangesOfUri(any(Uri.class));
-
-            verifyNoMoreInteractions(storIOContentResolver, internal);
-        }
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/TestItem.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/TestItem.java
deleted file mode 100644
index 7cfc5cc..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/get/TestItem.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.get;
-
-import java.util.concurrent.atomic.AtomicLong;
-
-class TestItem {
-
-    private static final AtomicLong COUNTER = new AtomicLong(0);
-
-    private Long id = COUNTER.incrementAndGet();
-
-    public Long getId() {
-        return id;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        TestItem testItem = (TestItem) o;
-
-        return !(id != null ? !id.equals(testItem.id) : testItem.id != null);
-    }
-
-    @Override
-    public int hashCode() {
-        return id != null ? id.hashCode() : 0;
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/DefaultPutResolverTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/DefaultPutResolverTest.java
deleted file mode 100644
index 94b454c..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/DefaultPutResolverTest.java
+++ /dev/null
@@ -1,260 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.InsertQuery;
-import com.pushtorefresh.storio.contentresolver.query.Query;
-import com.pushtorefresh.storio.contentresolver.query.UpdateQuery;
-
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import rx.functions.Func1;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class DefaultPutResolverTest {
-
-    /**
-     * Verifies behavior of {@link DefaultPutResolver} for "insert"
-     */
-    @Test
-    public void insert() {
-        final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
-        final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
-        final TestItem testItem = new TestItem(null); // item without id, should be inserted
-
-        when(storIOContentResolver.internal())
-                .thenReturn(internal);
-
-        final Uri expectedInsertedUri = mock(Uri.class);
-
-        final Query expectedQuery = Query.builder()
-                .uri(TestItem.CONTENT_URI)
-                .where(TestItem.COLUMN_ID + " = ?")
-                .whereArgs(testItem.getId())
-                .build();
-
-        final Cursor cursor = mock(Cursor.class);
-
-        when(internal.query(eq(expectedQuery)))
-                .thenReturn(cursor);
-
-        when(cursor.getCount())
-                .thenReturn(0); // No results -> insert should be performed
-
-        when(internal.insert(any(InsertQuery.class), any(ContentValues.class)))
-                .thenReturn(expectedInsertedUri);
-
-        final InsertQuery expectedInsertQuery = InsertQuery.builder()
-                .uri(TestItem.CONTENT_URI)
-                .build();
-
-        final PutResolver<TestItem> putResolver = new DefaultPutResolver<TestItem>() {
-            @NonNull
-            @Override
-            protected InsertQuery mapToInsertQuery(@NonNull TestItem object) {
-                return expectedInsertQuery;
-            }
-
-            @NonNull
-            @Override
-            protected UpdateQuery mapToUpdateQuery(@NonNull TestItem object) {
-                return UpdateQuery.builder()
-                        .uri(TestItem.CONTENT_URI)
-                        .where(TestItem.COLUMN_ID + " = ?")
-                        .whereArgs(object.getId())
-                        .build();
-            }
-
-            @NonNull
-            @Override
-            protected ContentValues mapToContentValues(@NonNull TestItem object) {
-                return TestItem.MAP_TO_CONTENT_VALUES.call(object);
-            }
-        };
-
-        final ContentValues expectedContentValues = TestItem.MAP_TO_CONTENT_VALUES.call(testItem);
-
-        // Performing Put that should "insert"
-        final PutResult putResult = putResolver.performPut(storIOContentResolver, testItem);
-
-        // checks that it asks db for results
-        verify(internal, times(1)).query(eq(expectedQuery));
-
-        // checks that cursor was closed
-        verify(cursor, times(1)).close();
-
-        // only one query should occur
-        verify(internal, times(1)).query(any(Query.class));
-
-        // checks that required insert was performed
-        verify(internal, times(1)).insert(eq(expectedInsertQuery), eq(expectedContentValues));
-
-        // only one insert should occur
-        verify(internal, times(1)).insert(any(InsertQuery.class), any(ContentValues.class));
-
-        // no updates should occur
-        verify(internal, times(0)).update(any(UpdateQuery.class), any(ContentValues.class));
-
-        // put result checks
-        assertTrue(putResult.wasInserted());
-        assertFalse(putResult.wasUpdated());
-
-        assertEquals(expectedInsertedUri, putResult.insertedUri());
-        assertNull(putResult.numberOfRowsUpdated());
-    }
-
-    /**
-     * Verifies behavior of {@link DefaultPutResolver} for "update"
-     */
-    @Test
-    public void update() {
-        final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
-        final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
-        final TestItem testItem = new TestItem(null); // item with some id, should be updated
-
-        when(storIOContentResolver.internal())
-                .thenReturn(internal);
-
-        final Query expectedQuery = Query.builder()
-                .uri(TestItem.CONTENT_URI)
-                .where(TestItem.COLUMN_ID + " = ?")
-                .whereArgs(testItem.getId())
-                .build();
-
-        final Cursor cursor = mock(Cursor.class);
-
-        when(internal.query(eq(expectedQuery)))
-                .thenReturn(cursor);
-
-        when(cursor.getCount())
-                .thenReturn(1); // Some rows already in db -> update should be performed
-
-        final Integer expectedNumberOfRowsUpdated = 1;
-
-        when(internal.update(any(UpdateQuery.class), any(ContentValues.class)))
-                .thenReturn(expectedNumberOfRowsUpdated);
-
-        final UpdateQuery expectedUpdateQuery = UpdateQuery.builder()
-                .uri(TestItem.CONTENT_URI)
-                .where(TestItem.COLUMN_ID + " = ?")
-                .whereArgs(testItem.getId())
-                .build();
-
-        final PutResolver<TestItem> putResolver = new DefaultPutResolver<TestItem>() {
-            @NonNull
-            @Override
-            protected InsertQuery mapToInsertQuery(@NonNull TestItem object) {
-                fail("Should not be called");
-                return null;
-            }
-
-            @NonNull
-            @Override
-            protected UpdateQuery mapToUpdateQuery(@NonNull TestItem object) {
-                return UpdateQuery.builder()
-                        .uri(TestItem.CONTENT_URI)
-                        .where(TestItem.COLUMN_ID + " = ?")
-                        .whereArgs(object.getId())
-                        .build();
-            }
-
-            @NonNull
-            @Override
-            protected ContentValues mapToContentValues(@NonNull TestItem object) {
-                return TestItem.MAP_TO_CONTENT_VALUES.call(object);
-            }
-        };
-
-        final ContentValues expectedContentValues = TestItem.MAP_TO_CONTENT_VALUES.call(testItem);
-
-        // Performing Put that should "update"
-        final PutResult putResult = putResolver.performPut(storIOContentResolver, testItem);
-
-        // checks that it asks db for results
-        verify(internal, times(1)).query(eq(expectedQuery));
-
-        // checks that cursor was closed
-        verify(cursor, times(1)).close();
-
-        // only one query should occur
-        verify(internal, times(1)).query(any(Query.class));
-
-        // checks that required update was performed
-        verify(internal, times(1)).update(eq(expectedUpdateQuery), eq(expectedContentValues));
-
-        // only one update should occur
-        verify(internal, times(1)).update(any(UpdateQuery.class), any(ContentValues.class));
-
-        // no inserts should occur
-        verify(internal, times(0)).insert(any(InsertQuery.class), any(ContentValues.class));
-
-        // put result checks
-        assertFalse(putResult.wasInserted());
-        assertTrue(putResult.wasUpdated());
-
-        assertEquals(expectedNumberOfRowsUpdated, putResult.numberOfRowsUpdated());
-        assertNull(putResult.insertedUri());
-    }
-
-    private static class TestItem {
-
-        final static Uri CONTENT_URI = mock(Uri.class);
-        final static String COLUMN_ID = "customIdColumnName";
-        @Nullable
-        private final Long id;
-        static final Func1<TestItem, ContentValues> MAP_TO_CONTENT_VALUES = new Func1<TestItem, ContentValues>() {
-
-            // ContentValues should be mocked for usage in tests (damn you Android...)
-            // but we can not mock equals() method
-            // so, we will return SAME ContentValues for object and assertEquals() will pass
-            @NonNull
-            private final Map<TestItem, ContentValues> map = new HashMap<TestItem, ContentValues>();
-
-            @NonNull
-            @Override
-            public ContentValues call(@NonNull TestItem testItem) {
-                if (map.containsKey(testItem)) {
-                    return map.get(testItem);
-                } else {
-                    final ContentValues contentValues = mock(ContentValues.class);
-
-                    when(contentValues.get(COLUMN_ID))
-                            .thenReturn(testItem.id);
-
-                    map.put(testItem, contentValues); // storing pair of mapping
-
-                    return contentValues;
-                }
-            }
-        };
-
-        TestItem(@Nullable Long id) {
-            this.id = id;
-        }
-
-        @Nullable
-        Long getId() {
-            return id;
-        }
-    }
-
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutCollectionOfObjectsTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutCollectionOfObjectsTest.java
deleted file mode 100644
index 9bf7030..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutCollectionOfObjectsTest.java
+++ /dev/null
@@ -1,155 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.content.ContentValues;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.InsertQuery;
-import com.pushtorefresh.storio.contentresolver.query.UpdateQuery;
-
-import org.junit.Test;
-import org.junit.experimental.runners.Enclosed;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-import rx.Observable;
-import rx.observers.TestSubscriber;
-
-import static java.util.Arrays.asList;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(Enclosed.class)
-public class PreparedPutCollectionOfObjectsTest {
-
-    public static class WithoutTypeMapping {
-
-        @Test
-        public void shouldPutObjectsWithoutTypeMappingBlocking() {
-            final PutObjectsStub putStub = PutObjectsStub.newPutStubForMultipleObjectsWithoutTypeMapping();
-
-            final PutResults<TestItem> putResults = putStub.storIOContentResolver
-                    .put()
-                    .objects(putStub.items)
-                    .withPutResolver(putStub.putResolver)
-                    .prepare()
-                    .executeAsBlocking();
-
-            putStub.verifyBehaviorForMultipleObjects(putResults);
-        }
-
-        @Test
-        public void shouldPutObjectsWithoutTypeMappingAsObservable() {
-            final PutObjectsStub putStub = PutObjectsStub.newPutStubForMultipleObjectsWithoutTypeMapping();
-
-            final Observable<PutResults<TestItem>> observable = putStub.storIOContentResolver
-                    .put()
-                    .objects(putStub.items)
-                    .withPutResolver(putStub.putResolver)
-                    .prepare()
-                    .createObservable();
-
-            putStub.verifyBehaviorForMultipleObjects(observable);
-        }
-    }
-
-    public static class WithTypeMapping {
-
-        @Test
-        public void shouldPutObjectsWithTypeMappingBlocking() {
-            final PutObjectsStub putStub = PutObjectsStub.newPutStubForMultipleObjectsWithTypeMapping();
-
-            final PutResults<TestItem> putResults = putStub.storIOContentResolver
-                    .put()
-                    .objects(putStub.items)
-                    .prepare()
-                    .executeAsBlocking();
-
-            putStub.verifyBehaviorForMultipleObjects(putResults);
-        }
-
-        @Test
-        public void shouldPutObjectsWithTypeMappingAsObservable() {
-            final PutObjectsStub putStub = PutObjectsStub.newPutStubForMultipleObjectsWithTypeMapping();
-
-            final Observable<PutResults<TestItem>> observable = putStub.storIOContentResolver
-                    .put()
-                    .objects(putStub.items)
-                    .prepare()
-                    .createObservable();
-
-            putStub.verifyBehaviorForMultipleObjects(observable);
-        }
-    }
-
-    public static class NoTypeMappingError {
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderBlocking() {
-            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
-            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
-
-            when(storIOContentResolver.internal()).thenReturn(internal);
-
-            when(storIOContentResolver.put()).thenReturn(new PreparedPut.Builder(storIOContentResolver));
-
-            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
-
-            final PreparedPut<PutResults<TestItem>> preparedPut = storIOContentResolver
-                    .put()
-                    .objects(items)
-                    .prepare();
-
-            try {
-                preparedPut.executeAsBlocking();
-                fail();
-            } catch (IllegalStateException expected) {
-                // it's okay, no type mapping was found
-            }
-
-            verify(storIOContentResolver).put();
-            verify(storIOContentResolver).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
-            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
-            verifyNoMoreInteractions(storIOContentResolver, internal);
-        }
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderAsObservable() {
-            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
-            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
-
-            when(storIOContentResolver.internal()).thenReturn(internal);
-
-            when(storIOContentResolver.put()).thenReturn(new PreparedPut.Builder(storIOContentResolver));
-
-            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
-
-            final TestSubscriber<PutResults<TestItem>> testSubscriber = new TestSubscriber<PutResults<TestItem>>();
-
-            storIOContentResolver
-                    .put()
-                    .objects(items)
-                    .prepare()
-                    .createObservable()
-                    .subscribe(testSubscriber);
-
-            testSubscriber.awaitTerminalEvent();
-            testSubscriber.assertNoValues();
-            testSubscriber.assertError(IllegalStateException.class);
-
-            verify(storIOContentResolver).put();
-            verify(storIOContentResolver).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
-            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
-            verifyNoMoreInteractions(storIOContentResolver, internal);
-        }
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValuesIterableTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValuesIterableTest.java
deleted file mode 100644
index 54d2329..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValuesIterableTest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.content.ContentValues;
-
-import org.junit.Test;
-
-import rx.Observable;
-
-public class PreparedPutContentValuesIterableTest {
-
-    @Test
-    public void putContentValuesIterableBlocking() {
-        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForMultipleContentValues();
-
-        final PutResults<ContentValues> putResults = putStub.storIOContentResolver
-                .put()
-                .contentValues(putStub.contentValues)
-                .withPutResolver(putStub.putResolver)
-                .prepare()
-                .executeAsBlocking();
-
-        putStub.verifyBehaviorForMultipleContentValues(putResults);
-    }
-
-    @Test
-    public void putContentValuesIterableObservable() {
-        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForMultipleContentValues();
-
-        final Observable<PutResults<ContentValues>> putResultsObservable = putStub.storIOContentResolver
-                .put()
-                .contentValues(putStub.contentValues)
-                .withPutResolver(putStub.putResolver)
-                .prepare()
-                .createObservable();
-
-        putStub.verifyBehaviorForMultipleContentValues(putResultsObservable);
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValuesTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValuesTest.java
deleted file mode 100644
index 31a584e..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutContentValuesTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import org.junit.Test;
-
-import rx.Observable;
-
-public class PreparedPutContentValuesTest {
-
-    @Test
-    public void putContentValuesBlocking() {
-        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForOneContentValues();
-
-        final PutResult putResult = putStub.storIOContentResolver
-                .put()
-                .contentValues(putStub.contentValues.get(0))
-                .withPutResolver(putStub.putResolver)
-                .prepare()
-                .executeAsBlocking();
-
-        putStub.verifyBehaviorForOneContentValues(putResult);
-    }
-
-    @Test
-    public void putContentValuesObservable() {
-        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForOneContentValues();
-
-        final Observable<PutResult> putResultObservable = putStub.storIOContentResolver
-                .put()
-                .contentValues(putStub.contentValues.get(0))
-                .withPutResolver(putStub.putResolver)
-                .prepare()
-                .createObservable();
-
-        putStub.verifyBehaviorForOneContentValues(putResultObservable);
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutObjectTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutObjectTest.java
deleted file mode 100644
index 465858a..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PreparedPutObjectTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.content.ContentValues;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.InsertQuery;
-import com.pushtorefresh.storio.contentresolver.query.UpdateQuery;
-
-import org.junit.Test;
-import org.junit.experimental.runners.Enclosed;
-import org.junit.runner.RunWith;
-
-import rx.Observable;
-import rx.observers.TestSubscriber;
-
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(Enclosed.class)
-public class PreparedPutObjectTest {
-
-    public static class WithTypeMapping {
-
-        @Test
-        public void shouldPutObjectWithoutTypeMappingBlocking() {
-            final PutObjectsStub putStub = PutObjectsStub.newPutStubForOneObjectWithoutTypeMapping();
-
-            final PutResult putResult = putStub.storIOContentResolver
-                    .put()
-                    .object(putStub.items.get(0))
-                    .withPutResolver(putStub.putResolver)
-                    .prepare()
-                    .executeAsBlocking();
-
-            putStub.verifyBehaviorForOneObject(putResult);
-        }
-
-        @Test
-        public void shouldPutObjectWithoutTypeMappingAsObservable() {
-            final PutObjectsStub putStub = PutObjectsStub.newPutStubForOneObjectWithoutTypeMapping();
-
-            final Observable<PutResult> putResultObservable = putStub.storIOContentResolver
-                    .put()
-                    .object(putStub.items.get(0))
-                    .withPutResolver(putStub.putResolver)
-                    .prepare()
-                    .createObservable();
-
-            putStub.verifyBehaviorForOneObject(putResultObservable);
-        }
-    }
-
-    public static class WithoutTypeMapping {
-
-        @Test
-        public void shouldPutObjectWithTypeMappingBlocking() {
-            final PutObjectsStub putStub = PutObjectsStub.newPutStubForOneObjectWithTypeMapping();
-
-            final PutResult putResult = putStub.storIOContentResolver
-                    .put()
-                    .object(putStub.items.get(0))
-                    .prepare()
-                    .executeAsBlocking();
-
-            putStub.verifyBehaviorForOneObject(putResult);
-        }
-
-        @Test
-        public void shouldPutObjectWithTypeMappingAsObservable() {
-            final PutObjectsStub putStub = PutObjectsStub.newPutStubForOneObjectWithTypeMapping();
-
-            final Observable<PutResult> putResultObservable = putStub.storIOContentResolver
-                    .put()
-                    .object(putStub.items.get(0))
-                    .prepare()
-                    .createObservable();
-
-            putStub.verifyBehaviorForOneObject(putResultObservable);
-        }
-    }
-
-    public static class NoTypeMappingError {
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderBlocking() {
-            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
-            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
-
-            when(storIOContentResolver.internal()).thenReturn(internal);
-
-            when(storIOContentResolver.put()).thenReturn(new PreparedPut.Builder(storIOContentResolver));
-
-            final PreparedPut<PutResult> preparedPut = storIOContentResolver
-                    .put()
-                    .object(TestItem.newInstance())
-                    .prepare();
-
-            try {
-                preparedPut.executeAsBlocking();
-                fail();
-            } catch (IllegalStateException expected) {
-                // it's okay, no type mapping was found
-            }
-
-            verify(storIOContentResolver).put();
-            verify(storIOContentResolver).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
-            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
-            verifyNoMoreInteractions(storIOContentResolver, internal);
-        }
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderAsObservable() {
-            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
-            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
-
-            when(storIOContentResolver.internal()).thenReturn(internal);
-
-            when(storIOContentResolver.put()).thenReturn(new PreparedPut.Builder(storIOContentResolver));
-
-            final TestSubscriber<PutResult> testSubscriber = new TestSubscriber<PutResult>();
-
-            storIOContentResolver
-                    .put()
-                    .object(TestItem.newInstance())
-                    .prepare()
-                    .createObservable()
-                    .subscribe(testSubscriber);
-
-            testSubscriber.awaitTerminalEvent();
-            testSubscriber.assertNoValues();
-            testSubscriber.assertError(IllegalStateException.class);
-
-            verify(storIOContentResolver).put();
-            verify(storIOContentResolver).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
-            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
-            verifyNoMoreInteractions(storIOContentResolver, internal);
-        }
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PutContentValuesStub.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PutContentValuesStub.java
deleted file mode 100644
index a80bcf6..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PutContentValuesStub.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.content.ContentValues;
-import android.net.Uri;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import rx.Observable;
-import rx.functions.Action1;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-// stub class to avoid violation of DRY in tests
-class PutContentValuesStub {
-
-    @NonNull
-    final StorIOContentResolver storIOContentResolver;
-
-    @NonNull
-    private final StorIOContentResolver.Internal internal;
-
-    @NonNull
-    final List<ContentValues> contentValues;
-
-    @NonNull
-    final PutResolver<ContentValues> putResolver;
-
-    @NonNull
-    private final Map<ContentValues, PutResult> contentValuesToPutResultsMap;
-
-    @SuppressWarnings("unchecked")
-    private PutContentValuesStub(int numberOfTestItems) {
-        storIOContentResolver = mock(StorIOContentResolver.class);
-        internal = mock(StorIOContentResolver.Internal.class);
-
-        when(storIOContentResolver.internal())
-                .thenReturn(internal);
-
-        when(storIOContentResolver.put())
-                .thenReturn(new PreparedPut.Builder(storIOContentResolver));
-
-        contentValues = new ArrayList<ContentValues>(numberOfTestItems);
-        contentValuesToPutResultsMap = new HashMap<ContentValues, PutResult>(numberOfTestItems);
-
-        for (int i = 0; i < numberOfTestItems; i++) {
-            final ContentValues cv = mock(ContentValues.class);
-            contentValues.add(cv);
-            contentValuesToPutResultsMap.put(cv, PutResult.newInsertResult(mock(Uri.class), TestItem.CONTENT_URI));
-        }
-
-        putResolver = (PutResolver<ContentValues>) mock(PutResolver.class);
-
-        when(putResolver.performPut(eq(storIOContentResolver), any(ContentValues.class)))
-                .thenReturn(PutResult.newInsertResult(mock(Uri.class), TestItem.CONTENT_URI));
-
-        for (final ContentValues cv : contentValues) {
-            final PutResult putResult = PutResult.newInsertResult(mock(Uri.class), mock(Uri.class));
-
-            contentValuesToPutResultsMap.put(cv, putResult);
-
-            when(putResolver.performPut(storIOContentResolver, cv))
-                    .thenReturn(putResult);
-        }
-    }
-
-    @NonNull
-    public static PutContentValuesStub newPutStubForOneContentValues() {
-        return new PutContentValuesStub(1);
-    }
-
-    @NonNull
-    public static PutContentValuesStub newPutStubForMultipleContentValues() {
-        return new PutContentValuesStub(3);
-    }
-
-    void verifyBehaviorForMultipleContentValues(@NonNull PutResults<ContentValues> putResults) {
-        // only one call to storIOContentResolver.put() should occur
-        verify(storIOContentResolver, times(1)).put();
-
-        // number of calls to putResolver's performPut() should be equal to number of objects
-        verify(putResolver, times(contentValues.size())).performPut(eq(storIOContentResolver), any(ContentValues.class));
-
-        for (final ContentValues cv : contentValues) {
-            // Put Operation should be performed once for each item
-            verify(putResolver, times(1)).performPut(storIOContentResolver, cv);
-        }
-    }
-
-    void verifyBehaviorForMultipleContentValues(@NonNull Observable<PutResults<ContentValues>> putResultsObservable) {
-        new ObservableBehaviorChecker<PutResults<ContentValues>>()
-                .observable(putResultsObservable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<PutResults<ContentValues>>() {
-                    @Override
-                    public void call(PutResults<ContentValues> putResults) {
-                        verifyBehaviorForMultipleContentValues(putResults);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-
-    void verifyBehaviorForOneContentValues(@NonNull PutResult putResult) {
-        Map<ContentValues, PutResult> putResultsMap = new HashMap<ContentValues, PutResult>(1);
-        putResultsMap.put(contentValues.get(0), putResult);
-        verifyBehaviorForMultipleContentValues(PutResults.newInstance(putResultsMap));
-    }
-
-    void verifyBehaviorForOneContentValues(@NonNull Observable<PutResult> putResultObservable) {
-        new ObservableBehaviorChecker<PutResult>()
-                .observable(putResultObservable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<PutResult>() {
-                    @Override
-                    public void call(PutResult putResult) {
-                        verifyBehaviorForOneContentValues(putResult);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PutObjectsStub.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PutObjectsStub.java
deleted file mode 100644
index 8e85e2d..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/PutObjectsStub.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.net.Uri;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
-import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
-import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import rx.Observable;
-import rx.functions.Action1;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-// stub class to avoid violation of DRY in tests
-class PutObjectsStub {
-
-    @NonNull
-    final StorIOContentResolver storIOContentResolver;
-
-    @NonNull
-    private final StorIOContentResolver.Internal internal;
-
-    @NonNull
-    final List<TestItem> items;
-
-    @NonNull
-    final PutResolver<TestItem> putResolver;
-
-    @NonNull
-    private final ContentResolverTypeMapping<TestItem> typeMapping;
-
-    @NonNull
-    private final Map<TestItem, PutResult> itemsToPutResultsMap;
-
-    private final boolean withTypeMapping;
-
-    @SuppressWarnings("unchecked")
-    private PutObjectsStub(boolean withTypeMapping, int numberOfTestItems) {
-        this.withTypeMapping = withTypeMapping;
-
-        storIOContentResolver = mock(StorIOContentResolver.class);
-        internal = mock(StorIOContentResolver.Internal.class);
-
-        when(storIOContentResolver.internal())
-                .thenReturn(internal);
-
-        when(storIOContentResolver.put())
-                .thenReturn(new PreparedPut.Builder(storIOContentResolver));
-
-        items = new ArrayList<TestItem>(numberOfTestItems);
-
-        for (int i = 0; i < numberOfTestItems; i++) {
-            final TestItem testItem = TestItem.newInstance();
-            items.add(testItem);
-        }
-
-        putResolver = (PutResolver<TestItem>) mock(PutResolver.class);
-        itemsToPutResultsMap = new HashMap<TestItem, PutResult>(numberOfTestItems);
-
-        for (final TestItem testItem : items) {
-            final PutResult putResult = PutResult.newInsertResult(mock(Uri.class), mock(Uri.class));
-            itemsToPutResultsMap.put(testItem, putResult);
-
-            when(putResolver.performPut(storIOContentResolver, testItem))
-                    .thenReturn(putResult);
-        }
-
-        typeMapping = mock(ContentResolverTypeMapping.class);
-
-        if (withTypeMapping) {
-            when(internal.typeMapping(TestItem.class)).thenReturn(typeMapping);
-            when(typeMapping.putResolver()).thenReturn(putResolver);
-        }
-    }
-
-    @NonNull
-    public static PutObjectsStub newPutStubForOneObjectWithoutTypeMapping() {
-        return new PutObjectsStub(false, 1);
-    }
-
-    @NonNull
-    public static PutObjectsStub newPutStubForOneObjectWithTypeMapping() {
-        return new PutObjectsStub(true, 1);
-    }
-
-    @NonNull
-    public static PutObjectsStub newPutStubForMultipleObjectsWithoutTypeMapping() {
-        return new PutObjectsStub(false, 3);
-    }
-
-    @NonNull
-    public static PutObjectsStub newPutStubForMultipleObjectsWithTypeMapping() {
-        return new PutObjectsStub(true, 3);
-    }
-
-    void verifyBehaviorForMultipleObjects(@NonNull PutResults<TestItem> putResults) {
-        if (items.size() > 1 || withTypeMapping) {
-            // should be called only once because of Performance!
-            verify(storIOContentResolver).internal();
-        } else {
-            verify(storIOContentResolver, never()).internal();
-        }
-
-        // should be called only once
-        verify(storIOContentResolver).put();
-
-        // number of calls to putResolver's performPut() should be equal to number of objects
-        verify(putResolver, times(items.size())).performPut(eq(storIOContentResolver), any(TestItem.class));
-
-        for (final TestItem testItem : items) {
-            // checks that put was performed for each item
-            verify(putResolver, times(1)).performPut(storIOContentResolver, testItem);
-
-            final PutResult expectedPutResult = itemsToPutResultsMap.get(testItem);
-            assertEquals(expectedPutResult, putResults.results().get(testItem));
-        }
-
-        assertEquals(itemsToPutResultsMap.size(), putResults.results().size());
-
-        if (withTypeMapping) {
-            verify(internal, times(items.size())).typeMapping(TestItem.class);
-            verify(typeMapping, times(items.size())).putResolver();
-        }
-
-        verifyNoMoreInteractions(storIOContentResolver, internal, typeMapping, putResolver);
-    }
-
-    void verifyBehaviorForMultipleObjects(@NonNull Observable<PutResults<TestItem>> putResultsObservable) {
-        new ObservableBehaviorChecker<PutResults<TestItem>>()
-                .observable(putResultsObservable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<PutResults<TestItem>>() {
-                    @Override
-                    public void call(PutResults<TestItem> putResults) {
-                        verifyBehaviorForMultipleObjects(putResults);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-
-    void verifyBehaviorForOneObject(@NonNull PutResult putResult) {
-        Map<TestItem, PutResult> putResultsMap = new HashMap<TestItem, PutResult>(1);
-        putResultsMap.put(items.get(0), putResult);
-        verifyBehaviorForMultipleObjects(PutResults.newInstance(putResultsMap));
-    }
-
-    void verifyBehaviorForOneObject(@NonNull Observable<PutResult> putResultObservable) {
-        new ObservableBehaviorChecker<PutResult>()
-                .observable(putResultObservable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<PutResult>() {
-                    @Override
-                    public void call(PutResult putResult) {
-                        verifyBehaviorForOneObject(putResult);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/TestItem.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/TestItem.java
deleted file mode 100644
index 708d4bb..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operation/put/TestItem.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.operation.put;
-
-import android.net.Uri;
-import android.support.annotation.NonNull;
-
-import static org.mockito.Mockito.mock;
-
-class TestItem {
-    static final Uri CONTENT_URI = mock(Uri.class);
-
-    private TestItem() {
-
-    }
-
-    @NonNull
-    static TestItem newInstance() {
-        return new TestItem();
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DefaultDeleteResolverTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DefaultDeleteResolverTest.java
new file mode 100644
index 0000000..6bc22df
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DefaultDeleteResolverTest.java
@@ -0,0 +1,68 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class DefaultDeleteResolverTest {
+
+    @Test
+    public void performDelete() {
+        final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
+        final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
+
+        when(storIOContentResolver.internal())
+                .thenReturn(internal);
+
+        final int expectedNumberOfRowsDeleted = 1;
+
+        when(internal.delete(any(DeleteQuery.class)))
+                .thenReturn(expectedNumberOfRowsDeleted);
+
+        final Uri expectedUri = mock(Uri.class);
+
+        final DeleteQuery expectedDeleteQuery = DeleteQuery.builder()
+                .uri(expectedUri)
+                .where("test where clause")
+                .whereArgs("test")
+                .build();
+
+        final TestItem testItem = TestItem.newInstance();
+
+        final DefaultDeleteResolver<TestItem> defaultDeleteResolver = new DefaultDeleteResolver<TestItem>() {
+            @NonNull
+            @Override
+            protected DeleteQuery mapToDeleteQuery(@NonNull TestItem object) {
+                assertSame(testItem, object);
+                return expectedDeleteQuery;
+            }
+        };
+
+        // Performing Delete Operation
+        final DeleteResult deleteResult = defaultDeleteResolver.performDelete(storIOContentResolver, testItem);
+
+        // checks that required delete was performed
+        verify(internal, times(1)).delete(expectedDeleteQuery);
+
+        // only one delete should be performed
+        verify(internal, times(1)).delete(any(DeleteQuery.class));
+
+        // delete result checks
+        assertEquals(expectedNumberOfRowsDeleted, deleteResult.numberOfRowsDeleted());
+        assertEquals(1, deleteResult.affectedUris().size());
+        assertTrue(deleteResult.affectedUris().contains(expectedUri));
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteByQueryStub.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteByQueryStub.java
new file mode 100644
index 0000000..e5b7ecd
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteByQueryStub.java
@@ -0,0 +1,89 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
+
+import rx.Observable;
+import rx.functions.Action1;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+// stub class to avoid violation of DRY in tests
+class DeleteByQueryStub {
+
+    @NonNull
+    final StorIOContentResolver storIOContentResolver;
+
+    @NonNull
+    private final StorIOContentResolver.Internal internal;
+
+    @NonNull
+    final DeleteQuery deleteQuery;
+
+    @NonNull
+    final DeleteResolver<DeleteQuery> deleteResolver;
+
+    @NonNull
+    private final DeleteResult deleteResult;
+
+    @SuppressWarnings("unchecked")
+    private DeleteByQueryStub() {
+        storIOContentResolver = mock(StorIOContentResolver.class);
+        internal = mock(StorIOContentResolver.Internal.class);
+
+        when(storIOContentResolver.internal())
+                .thenReturn(internal);
+
+        when(storIOContentResolver.delete())
+                .thenReturn(new PreparedDelete.Builder(storIOContentResolver));
+
+        deleteQuery = DeleteQuery.builder()
+                .uri(mock(Uri.class))
+                .build();
+
+        deleteResolver = mock(DeleteResolver.class);
+
+        deleteResult = DeleteResult.newInstance(1, deleteQuery.uri());
+
+        when(deleteResolver.performDelete(storIOContentResolver, deleteQuery))
+                .thenReturn(deleteResult);
+    }
+
+    @NonNull
+    static DeleteByQueryStub newInstance() {
+        return new DeleteByQueryStub();
+    }
+
+    void verifyBehavior(@NonNull DeleteResult actualDeleteResult) {
+        // checks that required delete was performed
+        verify(deleteResolver, times(1)).performDelete(storIOContentResolver, deleteQuery);
+
+        // only one call to DeleteResolver.performDelete() should occur
+        verify(deleteResolver, times(1)).performDelete(any(StorIOContentResolver.class), any(DeleteQuery.class));
+
+        // checks that actual delete result equals to expected
+        assertEquals(deleteResult, actualDeleteResult);
+    }
+
+    void verifyBehavior(@NonNull Observable<DeleteResult> deleteResultObservable) {
+        new ObservableBehaviorChecker<DeleteResult>()
+                .observable(deleteResultObservable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<DeleteResult>() {
+                    @Override
+                    public void call(DeleteResult deleteResult) {
+                        verifyBehavior(deleteResult);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteObjectsStub.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteObjectsStub.java
new file mode 100644
index 0000000..a0fc66c
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteObjectsStub.java
@@ -0,0 +1,171 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import rx.Observable;
+import rx.functions.Action1;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+// stub class to avoid violation of DRY in tests
+class DeleteObjectsStub {
+
+    @NonNull
+    final StorIOContentResolver storIOContentResolver;
+
+    @NonNull
+    private final StorIOContentResolver.Internal internal;
+
+    @NonNull
+    final List<TestItem> items;
+
+    @NonNull
+    final DeleteResolver<TestItem> deleteResolver;
+
+    @NonNull
+    private final ContentResolverTypeMapping<TestItem> typeMapping;
+
+    @NonNull
+    private final Map<TestItem, DeleteResult> testItemToDeleteResultMap;
+
+    private final boolean withTypeMapping;
+
+    @SuppressWarnings("unchecked")
+    private DeleteObjectsStub(boolean withTypeMapping, int numberOfTestItems) {
+        this.withTypeMapping = withTypeMapping;
+
+        storIOContentResolver = mock(StorIOContentResolver.class);
+        internal = mock(StorIOContentResolver.Internal.class);
+
+        when(storIOContentResolver.internal())
+                .thenReturn(internal);
+
+        when(storIOContentResolver.delete())
+                .thenReturn(new PreparedDelete.Builder(storIOContentResolver));
+
+        deleteResolver = mock(DeleteResolver.class);
+
+        items = new ArrayList<TestItem>(numberOfTestItems);
+        testItemToDeleteResultMap = new HashMap<TestItem, DeleteResult>(numberOfTestItems);
+
+        typeMapping = mock(ContentResolverTypeMapping.class);
+
+        if (withTypeMapping) {
+            when(typeMapping.deleteResolver()).thenReturn(deleteResolver);
+            when(internal.typeMapping(TestItem.class)).thenReturn(typeMapping);
+        }
+
+        for (int i = 0; i < numberOfTestItems; i++) {
+            final TestItem testItem = TestItem.newInstance();
+            items.add(testItem);
+
+            final Uri testItemUri = mock(Uri.class);
+
+            final DeleteResult deleteResult = DeleteResult.newInstance(1, testItemUri);
+            testItemToDeleteResultMap.put(testItem, deleteResult);
+
+            when(deleteResolver.performDelete(storIOContentResolver, testItem))
+                    .thenReturn(deleteResult);
+        }
+    }
+
+    @NonNull
+    static DeleteObjectsStub newInstanceForDeleteMultipleObjectsWithoutTypeMapping() {
+        return new DeleteObjectsStub(false, 3);
+    }
+
+    @NonNull
+    static DeleteObjectsStub newInstanceForDeleteMultipleObjectsWithTypeMapping() {
+        return new DeleteObjectsStub(true, 3);
+    }
+
+    @NonNull
+    static DeleteObjectsStub newInstanceForDeleteOneObjectWithoutTypeMapping() {
+        return new DeleteObjectsStub(false, 1);
+    }
+
+    @NonNull
+    static DeleteObjectsStub newInstanceForDeleteOneObjectWithTypeMapping() {
+        return new DeleteObjectsStub(true, 1);
+    }
+
+    void verifyBehaviorForDeleteMultipleObjects(@NonNull DeleteResults<TestItem> deleteResults) {
+        verify(storIOContentResolver).delete();
+
+        if (withTypeMapping || items.size() > 1) {
+            // should be called only once because of Performance!
+            verify(storIOContentResolver).internal();
+        }
+
+        // checks that delete was performed same amount of times as count of items
+        verify(deleteResolver, times(items.size())).performDelete(eq(storIOContentResolver), any(TestItem.class));
+
+        for (final TestItem testItem : items) {
+            // checks that delete was performed for each item
+            verify(deleteResolver, times(1)).performDelete(storIOContentResolver, testItem);
+
+            final DeleteResult expectedDeleteResult = testItemToDeleteResultMap.get(testItem);
+
+            // checks that delete results contains result of deletion of each item
+            assertEquals(expectedDeleteResult, deleteResults.results().get(testItem));
+        }
+
+        assertEquals(items.size(), deleteResults.results().size());
+
+        if (withTypeMapping) {
+            verify(internal, times(items.size())).typeMapping(TestItem.class);
+            verify(typeMapping, times(items.size())).deleteResolver();
+        }
+
+        verifyNoMoreInteractions(storIOContentResolver, internal, typeMapping, deleteResolver);
+    }
+
+    void verifyBehaviorForDeleteMultipleObjects(@NonNull Observable<DeleteResults<TestItem>> deleteResultsObservable) {
+        new ObservableBehaviorChecker<DeleteResults<TestItem>>()
+                .observable(deleteResultsObservable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<DeleteResults<TestItem>>() {
+                    @Override
+                    public void call(DeleteResults<TestItem> deleteResults) {
+                        verifyBehaviorForDeleteMultipleObjects(deleteResults);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+
+    void verifyBehaviorForDeleteOneObject(@NonNull DeleteResult deleteResult) {
+        Map<TestItem, DeleteResult> deleteResultsMap = new HashMap<TestItem, DeleteResult>(1);
+        deleteResultsMap.put(items.get(0), deleteResult);
+        verifyBehaviorForDeleteMultipleObjects(DeleteResults.newInstance(deleteResultsMap));
+    }
+
+    void verifyBehaviorForDeleteOneObject(@NonNull Observable<DeleteResult> deleteResultObservable) {
+        new ObservableBehaviorChecker<DeleteResult>()
+                .observable(deleteResultObservable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<DeleteResult>() {
+                    @Override
+                    public void call(DeleteResult deleteResult) {
+                        verifyBehaviorForDeleteOneObject(deleteResult);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResultTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResultTest.java
new file mode 100644
index 0000000..554f05d
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResultTest.java
@@ -0,0 +1,53 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import android.net.Uri;
+
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+public class DeleteResultTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void nullAffectedUri() {
+        DeleteResult.newInstance(1, (Uri) null);
+    }
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void nullAffectedUris() {
+        DeleteResult.newInstance(1, (Set<Uri>) null);
+    }
+
+    @Test
+    public void numberOfRowsDeleted() {
+        final DeleteResult deleteResult = DeleteResult.newInstance(3, mock(Uri.class));
+        assertEquals(3, deleteResult.numberOfRowsDeleted());
+    }
+
+    @Test
+    public void affectedUri() {
+        final Uri affectedUri = mock(Uri.class);
+        final DeleteResult deleteResult = DeleteResult.newInstance(2, affectedUri);
+        assertEquals(1, deleteResult.affectedUris().size());
+        assertTrue(deleteResult.affectedUris().contains(affectedUri));
+    }
+
+    @Test
+    public void affectedUris() {
+        final Set<Uri> affectedUris = new HashSet<Uri>();
+
+        affectedUris.add(mock(Uri.class));
+        affectedUris.add(mock(Uri.class));
+        affectedUris.add(mock(Uri.class));
+
+        final DeleteResult deleteResult = DeleteResult.newInstance(3, affectedUris);
+        assertEquals(affectedUris, deleteResult.affectedUris());
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResultsTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResultsTest.java
new file mode 100644
index 0000000..00f4440
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/DeleteResultsTest.java
@@ -0,0 +1,31 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import android.net.Uri;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+public class DeleteResultsTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void nullResults() {
+        DeleteResults.newInstance(null);
+    }
+
+    @Test
+    public void results() {
+        final Map<String, DeleteResult> results = new HashMap<String, DeleteResult>();
+        results.put("testString", DeleteResult.newInstance(1, mock(Uri.class)));
+        results.put("testString", DeleteResult.newInstance(1, mock(Uri.class)));
+
+        final DeleteResults<String> deleteResults = DeleteResults.newInstance(results);
+
+        assertEquals(results, deleteResults.results());
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteByQueryTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteByQueryTest.java
new file mode 100644
index 0000000..0798586
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteByQueryTest.java
@@ -0,0 +1,36 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import org.junit.Test;
+
+import rx.Observable;
+
+public class PreparedDeleteByQueryTest {
+
+    @Test
+    public void shouldDeleteByQueryBlocking() {
+        final DeleteByQueryStub deleteStub = DeleteByQueryStub.newInstance();
+
+        final DeleteResult deleteResult = deleteStub.storIOContentResolver
+                .delete()
+                .byQuery(deleteStub.deleteQuery)
+                .withDeleteResolver(deleteStub.deleteResolver)
+                .prepare()
+                .executeAsBlocking();
+
+        deleteStub.verifyBehavior(deleteResult);
+    }
+
+    @Test
+    public void shouldDeleteByQueryAsObservable() {
+        final DeleteByQueryStub deleteStub = DeleteByQueryStub.newInstance();
+
+        final Observable<DeleteResult> deleteResultObservable = deleteStub.storIOContentResolver
+                .delete()
+                .byQuery(deleteStub.deleteQuery)
+                .withDeleteResolver(deleteStub.deleteResolver)
+                .prepare()
+                .createObservable();
+
+        deleteStub.verifyBehavior(deleteResultObservable);
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteCollectionOfObjectsTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteCollectionOfObjectsTest.java
new file mode 100644
index 0000000..b702967
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteCollectionOfObjectsTest.java
@@ -0,0 +1,150 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+import rx.Observable;
+import rx.observers.TestSubscriber;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(Enclosed.class)
+public class PreparedDeleteCollectionOfObjectsTest {
+
+    public static class WithoutTypeMapping {
+
+        @Test
+        public void shouldDeleteObjectsWithoutTypeMappingBlocking() {
+            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteMultipleObjectsWithoutTypeMapping();
+
+            final DeleteResults<TestItem> deleteResults = deleteStub.storIOContentResolver
+                    .delete()
+                    .objects(deleteStub.items)
+                    .withDeleteResolver(deleteStub.deleteResolver)
+                    .prepare()
+                    .executeAsBlocking();
+
+            deleteStub.verifyBehaviorForDeleteMultipleObjects(deleteResults);
+        }
+
+        @Test
+        public void shouldDeleteObjectsWithoutTypeMappingAsObservable() {
+            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteMultipleObjectsWithoutTypeMapping();
+
+            final Observable<DeleteResults<TestItem>> observable = deleteStub.storIOContentResolver
+                    .delete()
+                    .objects(deleteStub.items)
+                    .withDeleteResolver(deleteStub.deleteResolver)
+                    .prepare()
+                    .createObservable();
+
+            deleteStub.verifyBehaviorForDeleteMultipleObjects(observable);
+        }
+    }
+
+    public static class WithTypeMapping {
+
+        @Test
+        public void shouldDeleteObjectsWithTypeMappingBlocking() {
+            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteMultipleObjectsWithTypeMapping();
+
+            final DeleteResults<TestItem> deleteResults = deleteStub.storIOContentResolver
+                    .delete()
+                    .objects(deleteStub.items)
+                    .prepare()
+                    .executeAsBlocking();
+
+            deleteStub.verifyBehaviorForDeleteMultipleObjects(deleteResults);
+        }
+
+        @Test
+        public void shouldDeleteObjectsWithTypeMappingAsObservable() {
+            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteMultipleObjectsWithTypeMapping();
+
+            final Observable<DeleteResults<TestItem>> observable = deleteStub.storIOContentResolver
+                    .delete()
+                    .objects(deleteStub.items)
+                    .prepare()
+                    .createObservable();
+
+            deleteStub.verifyBehaviorForDeleteMultipleObjects(observable);
+        }
+    }
+
+    public static class NoTypeMappingError {
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderBlocking() {
+            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
+            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
+
+            when(storIOContentResolver.internal()).thenReturn(internal);
+
+            when(storIOContentResolver.delete()).thenReturn(new PreparedDelete.Builder(storIOContentResolver));
+
+            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
+
+            final PreparedDelete<DeleteResults<TestItem>> preparedDelete = storIOContentResolver
+                    .delete()
+                    .objects(items)
+                    .prepare();
+
+            try {
+                preparedDelete.executeAsBlocking();
+                fail();
+            } catch (IllegalStateException expected) {
+                // it's okay, no type mapping was found
+            }
+
+            verify(storIOContentResolver).delete();
+            verify(storIOContentResolver).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).delete(any(DeleteQuery.class));
+            verifyNoMoreInteractions(storIOContentResolver, internal);
+        }
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderAsObservable() {
+            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
+            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
+
+            when(storIOContentResolver.internal()).thenReturn(internal);
+
+            when(storIOContentResolver.delete()).thenReturn(new PreparedDelete.Builder(storIOContentResolver));
+
+            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
+
+            final TestSubscriber<DeleteResults<TestItem>> testSubscriber = new TestSubscriber<DeleteResults<TestItem>>();
+
+            storIOContentResolver
+                    .delete()
+                    .objects(items)
+                    .prepare()
+                    .createObservable()
+                    .subscribe(testSubscriber);
+
+            testSubscriber.awaitTerminalEvent();
+            testSubscriber.assertNoValues();
+            testSubscriber.assertError(IllegalStateException.class);
+
+            verify(storIOContentResolver).delete();
+            verify(storIOContentResolver).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).delete(any(DeleteQuery.class));
+            verifyNoMoreInteractions(storIOContentResolver, internal);
+        }
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteObjectTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteObjectTest.java
new file mode 100644
index 0000000..e2aeb9c
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/PreparedDeleteObjectTest.java
@@ -0,0 +1,143 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import rx.Observable;
+import rx.observers.TestSubscriber;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(Enclosed.class)
+public class PreparedDeleteObjectTest {
+
+    public static class WithoutTypeMapping {
+
+        @Test
+        public void shouldDeleteObjectWithoutTypeMappingBlocking() {
+            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteOneObjectWithoutTypeMapping();
+
+            final DeleteResult deleteResult = deleteStub.storIOContentResolver
+                    .delete()
+                    .object(deleteStub.items.get(0))
+                    .withDeleteResolver(deleteStub.deleteResolver)
+                    .prepare()
+                    .executeAsBlocking();
+
+            deleteStub.verifyBehaviorForDeleteOneObject(deleteResult);
+        }
+
+        @Test
+        public void shouldDeleteObjectWithoutTypeMappingAsObservable() {
+            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteOneObjectWithoutTypeMapping();
+
+            final Observable<DeleteResult> observable = deleteStub.storIOContentResolver
+                    .delete()
+                    .object(deleteStub.items.get(0))
+                    .withDeleteResolver(deleteStub.deleteResolver)
+                    .prepare()
+                    .createObservable();
+
+            deleteStub.verifyBehaviorForDeleteOneObject(observable);
+        }
+    }
+
+    public static class WithTypeMapping {
+
+        @Test
+        public void shouldDeleteObjectWithTypeMappingBlocking() {
+            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteOneObjectWithTypeMapping();
+
+            final DeleteResult deleteResult = deleteStub.storIOContentResolver
+                    .delete()
+                    .object(deleteStub.items.get(0))
+                    .prepare()
+                    .executeAsBlocking();
+
+            deleteStub.verifyBehaviorForDeleteOneObject(deleteResult);
+        }
+
+        @Test
+        public void shouldDeleteObjectWithTypeMappingAsObservable() {
+            final DeleteObjectsStub deleteStub = DeleteObjectsStub.newInstanceForDeleteOneObjectWithTypeMapping();
+
+            final Observable<DeleteResult> observable = deleteStub.storIOContentResolver
+                    .delete()
+                    .object(deleteStub.items.get(0))
+                    .prepare()
+                    .createObservable();
+
+            deleteStub.verifyBehaviorForDeleteOneObject(observable);
+        }
+    }
+
+    public static class NoTypeMappingError {
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderBlocking() {
+            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
+            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
+
+            when(storIOContentResolver.internal()).thenReturn(internal);
+
+            when(storIOContentResolver.delete()).thenReturn(new PreparedDelete.Builder(storIOContentResolver));
+
+            final PreparedDelete<DeleteResult> preparedDelete = storIOContentResolver
+                    .delete()
+                    .object(TestItem.newInstance())
+                    .prepare();
+
+            try {
+                preparedDelete.executeAsBlocking();
+                fail();
+            } catch (IllegalStateException expected) {
+                // it's okay, no type mapping was found
+            }
+
+            verify(storIOContentResolver).delete();
+            verify(storIOContentResolver).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).delete(any(DeleteQuery.class));
+            verifyNoMoreInteractions(storIOContentResolver, internal);
+        }
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderAsObservable() {
+            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
+            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
+
+            when(storIOContentResolver.internal()).thenReturn(internal);
+
+            when(storIOContentResolver.delete()).thenReturn(new PreparedDelete.Builder(storIOContentResolver));
+
+            final TestSubscriber<DeleteResult> testSubscriber = new TestSubscriber<DeleteResult>();
+
+            storIOContentResolver
+                    .delete()
+                    .object(TestItem.newInstance())
+                    .prepare()
+                    .createObservable()
+                    .subscribe(testSubscriber);
+
+            testSubscriber.awaitTerminalEvent();
+            testSubscriber.assertNoValues();
+            testSubscriber.assertError(IllegalStateException.class);
+
+            verify(storIOContentResolver).delete();
+            verify(storIOContentResolver).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).delete(any(DeleteQuery.class));
+            verifyNoMoreInteractions(storIOContentResolver, internal);
+        }
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/TestItem.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/TestItem.java
new file mode 100644
index 0000000..eff0704
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/delete/TestItem.java
@@ -0,0 +1,15 @@
+package com.pushtorefresh.storio.contentresolver.operations.delete;
+
+import android.support.annotation.NonNull;
+
+class TestItem {
+
+    private TestItem() {
+
+    }
+
+    @NonNull
+    public static TestItem newInstance() {
+        return new TestItem();
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/DefaultGetResolverTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/DefaultGetResolverTest.java
new file mode 100644
index 0000000..b5a6322
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/DefaultGetResolverTest.java
@@ -0,0 +1,61 @@
+package com.pushtorefresh.storio.contentresolver.operations.get;
+
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
+
+import org.junit.Test;
+
+import static junit.framework.Assert.assertSame;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class DefaultGetResolverTest {
+
+    @Test
+    public void query() {
+        final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
+        final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
+
+        final Query query = Query.builder()
+                .uri(mock(Uri.class))
+                .build();
+
+        final Cursor expectedCursor = mock(Cursor.class);
+
+        when(storIOContentResolver.internal())
+                .thenReturn(internal);
+
+        when(internal.query(query))
+                .thenReturn(expectedCursor);
+
+        final GetResolver<TestItem> defaultGetResolver = new DefaultGetResolver<TestItem>() {
+            @NonNull
+            @Override
+            public TestItem mapFromCursor(@NonNull Cursor cursor) {
+                assertSame(expectedCursor, cursor);
+                return new TestItem();
+            }
+        };
+
+        final Cursor actualCursor = defaultGetResolver.performGet(storIOContentResolver, query);
+
+        // only one request should occur
+        verify(internal, times(1)).query(any(Query.class));
+
+        // and this request should be equals to original
+        verify(internal, times(1)).query(query);
+
+        assertSame(expectedCursor, actualCursor);
+    }
+
+    private static class TestItem {
+
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/GetCursorStub.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/GetCursorStub.java
new file mode 100644
index 0000000..560c4ab
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/GetCursorStub.java
@@ -0,0 +1,95 @@
+package com.pushtorefresh.storio.contentresolver.operations.get;
+
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.Changes;
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
+import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
+
+import rx.Observable;
+import rx.functions.Action1;
+
+import static junit.framework.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+class GetCursorStub {
+
+    @NonNull
+    final StorIOContentResolver storIOContentResolver;
+
+    @NonNull
+    private final StorIOContentResolver.Internal internal;
+
+    @NonNull
+    final Query query;
+
+    @NonNull
+    final GetResolver<Cursor> getResolver;
+
+    @NonNull
+    final Cursor cursor;
+
+    @SuppressWarnings("unchecked")
+    private GetCursorStub() {
+        storIOContentResolver = mock(StorIOContentResolver.class);
+        internal = mock(StorIOContentResolver.Internal.class);
+
+        query = Query.builder()
+                .uri(mock(Uri.class))
+                .build();
+
+        getResolver = mock(GetResolver.class);
+        cursor = mock(Cursor.class);
+
+        when(storIOContentResolver.internal())
+                .thenReturn(internal);
+
+        when(storIOContentResolver.get())
+                .thenReturn(new PreparedGet.Builder(storIOContentResolver));
+
+        when(getResolver.performGet(storIOContentResolver, query))
+                .thenReturn(cursor);
+
+        when(storIOContentResolver.observeChangesOfUri(query.uri()))
+                .thenReturn(Observable.<Changes>empty());
+
+        when(getResolver.mapFromCursor(cursor))
+                .thenReturn(cursor);
+    }
+
+    @NonNull
+    static GetCursorStub newInstance() {
+        return new GetCursorStub();
+    }
+
+    void verifyQueryBehaviorForCursor(@NonNull Cursor actualCursor) {
+        verify(storIOContentResolver, times(1)).get();
+        verify(getResolver, times(1)).performGet(storIOContentResolver, query);
+        assertSame(cursor, actualCursor);
+        verify(cursor, times(0)).close();
+        verifyNoMoreInteractions(storIOContentResolver, internal, getResolver, cursor);
+    }
+
+    void verifyQueryBehaviorForCursor(@NonNull Observable<Cursor> observable) {
+        new ObservableBehaviorChecker<Cursor>()
+                .observable(observable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<Cursor>() {
+                    @Override
+                    public void call(Cursor cursor) {
+                        // Get Operation should be subscribed to changes of Uri
+                        verify(storIOContentResolver).observeChangesOfUri(query.uri());
+
+                        verifyQueryBehaviorForCursor(cursor);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/GetObjectsStub.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/GetObjectsStub.java
new file mode 100644
index 0000000..fd35586
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/GetObjectsStub.java
@@ -0,0 +1,187 @@
+package com.pushtorefresh.storio.contentresolver.operations.get;
+
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.Changes;
+import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
+import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import rx.Observable;
+import rx.functions.Action1;
+
+import static com.pushtorefresh.storio.test.Asserts.assertThatListIsImmutable;
+import static junit.framework.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+class GetObjectsStub {
+
+    @NonNull
+    final StorIOContentResolver storIOContentResolver;
+
+    @NonNull
+    private final StorIOContentResolver.Internal internal;
+
+    @NonNull
+    final Query query;
+
+    @NonNull
+    final List<TestItem> items;
+
+    @NonNull
+    final GetResolver<TestItem> getResolver;
+
+    @NonNull
+    final Cursor cursor;
+
+    @NonNull
+    private final ContentResolverTypeMapping<TestItem> typeMapping;
+
+    private final boolean withTypeMapping;
+
+    @SuppressWarnings("unchecked")
+    private GetObjectsStub(boolean withTypeMapping) {
+        this.withTypeMapping = withTypeMapping;
+
+        storIOContentResolver = mock(StorIOContentResolver.class);
+        internal = mock(StorIOContentResolver.Internal.class);
+
+        query = Query.builder()
+                .uri(mock(Uri.class))
+                .build();
+
+        getResolver = mock(GetResolver.class);
+        cursor = mock(Cursor.class);
+
+        items = new ArrayList<TestItem>();
+        items.add(new TestItem());
+        items.add(new TestItem());
+        items.add(new TestItem());
+
+        when(storIOContentResolver.internal())
+                .thenReturn(internal);
+
+        when(cursor.moveToNext())
+                .thenAnswer(new Answer<Boolean>() {
+                    int invocationsCount = 0;
+
+                    @Override
+                    public Boolean answer(InvocationOnMock invocation) throws Throwable {
+                        return invocationsCount++ < items.size();
+                    }
+                });
+
+        when(cursor.getCount())
+                .thenReturn(items.size());
+
+        when(storIOContentResolver.get())
+                .thenReturn(new PreparedGet.Builder(storIOContentResolver));
+
+        when(getResolver.performGet(storIOContentResolver, query))
+                .thenReturn(cursor);
+
+        when(storIOContentResolver.observeChangesOfUri(query.uri()))
+                .thenReturn(Observable.<Changes>empty());
+
+        when(getResolver.mapFromCursor(cursor))
+                .thenAnswer(new Answer<TestItem>() {
+                    int invocationsCount = 0;
+
+                    @Override
+                    public TestItem answer(InvocationOnMock invocation) throws Throwable {
+                        final TestItem testItem = items.get(invocationsCount);
+                        invocationsCount++;
+                        return testItem;
+                    }
+                });
+
+        typeMapping = mock(ContentResolverTypeMapping.class);
+
+        if (withTypeMapping) {
+            when(internal.typeMapping(TestItem.class)).thenReturn(typeMapping);
+            when(typeMapping.getResolver()).thenReturn(getResolver);
+        }
+    }
+
+    @NonNull
+    static GetObjectsStub newStubWithoutTypeMapping() {
+        return new GetObjectsStub(false);
+    }
+
+    @NonNull
+    static GetObjectsStub newStubWithTypeMapping() {
+        return new GetObjectsStub(true);
+    }
+
+    void verifyBehavior(@NonNull List<TestItem> actualList) {
+        // should be called once
+        verify(storIOContentResolver).get();
+
+        // should be called once
+        verify(getResolver).performGet(storIOContentResolver, query);
+
+        // should be called only once because of Performance!
+        verify(cursor).getCount();
+
+        // should be called same number of times as count of items in cursor + 1 (last -> false)
+        verify(cursor, times(items.size() + 1)).moveToNext();
+
+        // should be called same number of times as count of items in cursor
+        verify(getResolver, times(items.size())).mapFromCursor(cursor);
+
+        // cursor should be closed!
+        verify(cursor).close();
+
+        // checks that items are okay
+        assertEquals(items, actualList);
+
+        // returned list should be immutable
+        assertThatListIsImmutable(actualList);
+
+        if (withTypeMapping) {
+            // should be called only once because of Performance!
+            verify(storIOContentResolver).internal();
+
+            // should be called only once because of Performance!
+            verify(internal).typeMapping(TestItem.class);
+
+            // should be called only once
+            verify(typeMapping).getResolver();
+        }
+
+        verifyNoMoreInteractions(storIOContentResolver, internal, getResolver, cursor);
+    }
+
+    void verifyBehavior(@NonNull Observable<List<TestItem>> observable) {
+        when(storIOContentResolver.observeChangesOfUri(query.uri()))
+                .thenReturn(Observable.<Changes>empty());
+
+        new ObservableBehaviorChecker<List<TestItem>>()
+                .observable(observable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<List<TestItem>>() {
+                    @Override
+                    public void call(List<TestItem> testItems) {
+                        // Get Operation should be subscribed to changes of Uri!
+                        verify(storIOContentResolver).observeChangesOfUri(query.uri());
+
+                        verifyBehavior(testItems);
+                    }
+                })
+                .checkBehaviorOfObservable();
+
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetCursorTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetCursorTest.java
new file mode 100644
index 0000000..ae29fe5
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetCursorTest.java
@@ -0,0 +1,42 @@
+package com.pushtorefresh.storio.contentresolver.operations.get;
+
+import android.database.Cursor;
+
+import org.junit.Test;
+
+import rx.Observable;
+
+public class PreparedGetCursorTest {
+
+    @Test
+    public void getCursorBlocking() {
+        final GetCursorStub getStub = GetCursorStub.newInstance();
+
+        final Cursor cursor = getStub.storIOContentResolver
+                .get()
+                .cursor()
+                .withQuery(getStub.query)
+                .withGetResolver(getStub.getResolver)
+                .prepare()
+                .executeAsBlocking();
+
+        getStub.verifyQueryBehaviorForCursor(cursor);
+    }
+
+
+    @Test
+    public void getCursorObservable() {
+        final GetCursorStub getStub = GetCursorStub.newInstance();
+
+        final Observable<Cursor> cursorObservable = getStub.storIOContentResolver
+                .get()
+                .cursor()
+                .withQuery(getStub.query)
+                .withGetResolver(getStub.getResolver)
+                .prepare()
+                .createObservable()
+                .take(1);
+
+        getStub.verifyQueryBehaviorForCursor(cursorObservable);
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetListOfObjectsTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetListOfObjectsTest.java
new file mode 100644
index 0000000..91d49f7
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/PreparedGetListOfObjectsTest.java
@@ -0,0 +1,161 @@
+package com.pushtorefresh.storio.contentresolver.operations.get;
+
+import android.net.Uri;
+
+import com.pushtorefresh.storio.contentresolver.Changes;
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
+
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+import rx.Observable;
+import rx.observers.TestSubscriber;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(Enclosed.class)
+public class PreparedGetListOfObjectsTest {
+
+    public static class WithoutTypeMapping {
+
+        @Test
+        public void shouldGetListOfObjectsWithoutTypeMappingBlocking() {
+            final GetObjectsStub getStub = GetObjectsStub.newStubWithoutTypeMapping();
+
+            final List<TestItem> testItems = getStub.storIOContentResolver
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(getStub.query)
+                    .withGetResolver(getStub.getResolver)
+                    .prepare()
+                    .executeAsBlocking();
+
+            getStub.verifyBehavior(testItems);
+        }
+
+        @Test
+        public void shouldGetListOfObjectsWithoutTypeMappingAsObservable() {
+            final GetObjectsStub getStub = GetObjectsStub.newStubWithoutTypeMapping();
+
+            final Observable<List<TestItem>> testItemsObservable = getStub.storIOContentResolver
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(getStub.query)
+                    .withGetResolver(getStub.getResolver)
+                    .prepare()
+                    .createObservable()
+                    .take(1);
+
+            getStub.verifyBehavior(testItemsObservable);
+        }
+    }
+
+    public static class WithTypeMapping {
+
+        @Test
+        public void shouldGetListOfObjectsWithTypeMappingBlocking() {
+            final GetObjectsStub getStub = GetObjectsStub.newStubWithTypeMapping();
+
+            final List<TestItem> testItems = getStub.storIOContentResolver
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(getStub.query)
+                    .prepare()
+                    .executeAsBlocking();
+
+            getStub.verifyBehavior(testItems);
+        }
+
+        @Test
+        public void shouldGetListOfObjectsWithTypeMappingAsObservable() {
+            final GetObjectsStub getStub = GetObjectsStub.newStubWithTypeMapping();
+
+            final Observable<List<TestItem>> testItemsObservable = getStub.storIOContentResolver
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(getStub.query)
+                    .prepare()
+                    .createObservable()
+                    .take(1);
+
+            getStub.verifyBehavior(testItemsObservable);
+        }
+    }
+
+    public static class NoTypeMappingError {
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAccessingContentProviderBlocking() {
+            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
+            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
+
+            when(storIOContentResolver.internal()).thenReturn(internal);
+
+            when(storIOContentResolver.get()).thenReturn(new PreparedGet.Builder(storIOContentResolver));
+
+            final PreparedGet<List<TestItem>> preparedGet = storIOContentResolver
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(mock(Query.class))
+                    .prepare();
+
+            try {
+                preparedGet.executeAsBlocking();
+                fail();
+            } catch (IllegalStateException expected) {
+                // it's okay, no type mapping was found
+            }
+
+            verify(storIOContentResolver).get();
+            verify(storIOContentResolver).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).query(any(Query.class));
+            verifyNoMoreInteractions(storIOContentResolver, internal);
+        }
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAccessingContentProviderAsObservable() {
+            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
+            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
+
+            when(storIOContentResolver.internal()).thenReturn(internal);
+
+            when(storIOContentResolver.get()).thenReturn(new PreparedGet.Builder(storIOContentResolver));
+
+            when(storIOContentResolver.observeChangesOfUri(any(Uri.class)))
+                    .thenReturn(Observable.<Changes>empty());
+
+            final TestSubscriber<List<TestItem>> testSubscriber = new TestSubscriber<List<TestItem>>();
+
+            storIOContentResolver
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(mock(Query.class))
+                    .prepare()
+                    .createObservable()
+                    .subscribe(testSubscriber);
+
+            testSubscriber.awaitTerminalEvent();
+            testSubscriber.assertNoValues();
+            testSubscriber.assertError(IllegalStateException.class);
+
+            verify(storIOContentResolver).get();
+            verify(storIOContentResolver).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).query(any(Query.class));
+            verify(storIOContentResolver).observeChangesOfUri(any(Uri.class));
+
+            verifyNoMoreInteractions(storIOContentResolver, internal);
+        }
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/TestItem.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/TestItem.java
new file mode 100644
index 0000000..9c1a783
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/get/TestItem.java
@@ -0,0 +1,29 @@
+package com.pushtorefresh.storio.contentresolver.operations.get;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+class TestItem {
+
+    private static final AtomicLong COUNTER = new AtomicLong(0);
+
+    private Long id = COUNTER.incrementAndGet();
+
+    public Long getId() {
+        return id;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        TestItem testItem = (TestItem) o;
+
+        return !(id != null ? !id.equals(testItem.id) : testItem.id != null);
+    }
+
+    @Override
+    public int hashCode() {
+        return id != null ? id.hashCode() : 0;
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/DefaultPutResolverTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/DefaultPutResolverTest.java
new file mode 100644
index 0000000..2231538
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/DefaultPutResolverTest.java
@@ -0,0 +1,260 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
+import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import rx.functions.Func1;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class DefaultPutResolverTest {
+
+    /**
+     * Verifies behavior of {@link DefaultPutResolver} for "insert"
+     */
+    @Test
+    public void insert() {
+        final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
+        final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
+        final TestItem testItem = new TestItem(null); // item without id, should be inserted
+
+        when(storIOContentResolver.internal())
+                .thenReturn(internal);
+
+        final Uri expectedInsertedUri = mock(Uri.class);
+
+        final Query expectedQuery = Query.builder()
+                .uri(TestItem.CONTENT_URI)
+                .where(TestItem.COLUMN_ID + " = ?")
+                .whereArgs(testItem.getId())
+                .build();
+
+        final Cursor cursor = mock(Cursor.class);
+
+        when(internal.query(eq(expectedQuery)))
+                .thenReturn(cursor);
+
+        when(cursor.getCount())
+                .thenReturn(0); // No results -> insert should be performed
+
+        when(internal.insert(any(InsertQuery.class), any(ContentValues.class)))
+                .thenReturn(expectedInsertedUri);
+
+        final InsertQuery expectedInsertQuery = InsertQuery.builder()
+                .uri(TestItem.CONTENT_URI)
+                .build();
+
+        final PutResolver<TestItem> putResolver = new DefaultPutResolver<TestItem>() {
+            @NonNull
+            @Override
+            protected InsertQuery mapToInsertQuery(@NonNull TestItem object) {
+                return expectedInsertQuery;
+            }
+
+            @NonNull
+            @Override
+            protected UpdateQuery mapToUpdateQuery(@NonNull TestItem object) {
+                return UpdateQuery.builder()
+                        .uri(TestItem.CONTENT_URI)
+                        .where(TestItem.COLUMN_ID + " = ?")
+                        .whereArgs(object.getId())
+                        .build();
+            }
+
+            @NonNull
+            @Override
+            protected ContentValues mapToContentValues(@NonNull TestItem object) {
+                return TestItem.MAP_TO_CONTENT_VALUES.call(object);
+            }
+        };
+
+        final ContentValues expectedContentValues = TestItem.MAP_TO_CONTENT_VALUES.call(testItem);
+
+        // Performing Put that should "insert"
+        final PutResult putResult = putResolver.performPut(storIOContentResolver, testItem);
+
+        // checks that it asks db for results
+        verify(internal, times(1)).query(eq(expectedQuery));
+
+        // checks that cursor was closed
+        verify(cursor, times(1)).close();
+
+        // only one query should occur
+        verify(internal, times(1)).query(any(Query.class));
+
+        // checks that required insert was performed
+        verify(internal, times(1)).insert(eq(expectedInsertQuery), eq(expectedContentValues));
+
+        // only one insert should occur
+        verify(internal, times(1)).insert(any(InsertQuery.class), any(ContentValues.class));
+
+        // no updates should occur
+        verify(internal, times(0)).update(any(UpdateQuery.class), any(ContentValues.class));
+
+        // put result checks
+        assertTrue(putResult.wasInserted());
+        assertFalse(putResult.wasUpdated());
+
+        assertEquals(expectedInsertedUri, putResult.insertedUri());
+        assertNull(putResult.numberOfRowsUpdated());
+    }
+
+    /**
+     * Verifies behavior of {@link DefaultPutResolver} for "update"
+     */
+    @Test
+    public void update() {
+        final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
+        final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
+        final TestItem testItem = new TestItem(null); // item with some id, should be updated
+
+        when(storIOContentResolver.internal())
+                .thenReturn(internal);
+
+        final Query expectedQuery = Query.builder()
+                .uri(TestItem.CONTENT_URI)
+                .where(TestItem.COLUMN_ID + " = ?")
+                .whereArgs(testItem.getId())
+                .build();
+
+        final Cursor cursor = mock(Cursor.class);
+
+        when(internal.query(eq(expectedQuery)))
+                .thenReturn(cursor);
+
+        when(cursor.getCount())
+                .thenReturn(1); // Some rows already in db -> update should be performed
+
+        final Integer expectedNumberOfRowsUpdated = 1;
+
+        when(internal.update(any(UpdateQuery.class), any(ContentValues.class)))
+                .thenReturn(expectedNumberOfRowsUpdated);
+
+        final UpdateQuery expectedUpdateQuery = UpdateQuery.builder()
+                .uri(TestItem.CONTENT_URI)
+                .where(TestItem.COLUMN_ID + " = ?")
+                .whereArgs(testItem.getId())
+                .build();
+
+        final PutResolver<TestItem> putResolver = new DefaultPutResolver<TestItem>() {
+            @NonNull
+            @Override
+            protected InsertQuery mapToInsertQuery(@NonNull TestItem object) {
+                fail("Should not be called");
+                return null;
+            }
+
+            @NonNull
+            @Override
+            protected UpdateQuery mapToUpdateQuery(@NonNull TestItem object) {
+                return UpdateQuery.builder()
+                        .uri(TestItem.CONTENT_URI)
+                        .where(TestItem.COLUMN_ID + " = ?")
+                        .whereArgs(object.getId())
+                        .build();
+            }
+
+            @NonNull
+            @Override
+            protected ContentValues mapToContentValues(@NonNull TestItem object) {
+                return TestItem.MAP_TO_CONTENT_VALUES.call(object);
+            }
+        };
+
+        final ContentValues expectedContentValues = TestItem.MAP_TO_CONTENT_VALUES.call(testItem);
+
+        // Performing Put that should "update"
+        final PutResult putResult = putResolver.performPut(storIOContentResolver, testItem);
+
+        // checks that it asks db for results
+        verify(internal, times(1)).query(eq(expectedQuery));
+
+        // checks that cursor was closed
+        verify(cursor, times(1)).close();
+
+        // only one query should occur
+        verify(internal, times(1)).query(any(Query.class));
+
+        // checks that required update was performed
+        verify(internal, times(1)).update(eq(expectedUpdateQuery), eq(expectedContentValues));
+
+        // only one update should occur
+        verify(internal, times(1)).update(any(UpdateQuery.class), any(ContentValues.class));
+
+        // no inserts should occur
+        verify(internal, times(0)).insert(any(InsertQuery.class), any(ContentValues.class));
+
+        // put result checks
+        assertFalse(putResult.wasInserted());
+        assertTrue(putResult.wasUpdated());
+
+        assertEquals(expectedNumberOfRowsUpdated, putResult.numberOfRowsUpdated());
+        assertNull(putResult.insertedUri());
+    }
+
+    private static class TestItem {
+
+        final static Uri CONTENT_URI = mock(Uri.class);
+        final static String COLUMN_ID = "customIdColumnName";
+        @Nullable
+        private final Long id;
+        static final Func1<TestItem, ContentValues> MAP_TO_CONTENT_VALUES = new Func1<TestItem, ContentValues>() {
+
+            // ContentValues should be mocked for usage in tests (damn you Android...)
+            // but we can not mock equals() method
+            // so, we will return SAME ContentValues for object and assertEquals() will pass
+            @NonNull
+            private final Map<TestItem, ContentValues> map = new HashMap<TestItem, ContentValues>();
+
+            @NonNull
+            @Override
+            public ContentValues call(@NonNull TestItem testItem) {
+                if (map.containsKey(testItem)) {
+                    return map.get(testItem);
+                } else {
+                    final ContentValues contentValues = mock(ContentValues.class);
+
+                    when(contentValues.get(COLUMN_ID))
+                            .thenReturn(testItem.id);
+
+                    map.put(testItem, contentValues); // storing pair of mapping
+
+                    return contentValues;
+                }
+            }
+        };
+
+        TestItem(@Nullable Long id) {
+            this.id = id;
+        }
+
+        @Nullable
+        Long getId() {
+            return id;
+        }
+    }
+
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutCollectionOfObjectsTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutCollectionOfObjectsTest.java
new file mode 100644
index 0000000..787c61a
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutCollectionOfObjectsTest.java
@@ -0,0 +1,155 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.content.ContentValues;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;
+import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;
+
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+import rx.Observable;
+import rx.observers.TestSubscriber;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(Enclosed.class)
+public class PreparedPutCollectionOfObjectsTest {
+
+    public static class WithoutTypeMapping {
+
+        @Test
+        public void shouldPutObjectsWithoutTypeMappingBlocking() {
+            final PutObjectsStub putStub = PutObjectsStub.newPutStubForMultipleObjectsWithoutTypeMapping();
+
+            final PutResults<TestItem> putResults = putStub.storIOContentResolver
+                    .put()
+                    .objects(putStub.items)
+                    .withPutResolver(putStub.putResolver)
+                    .prepare()
+                    .executeAsBlocking();
+
+            putStub.verifyBehaviorForMultipleObjects(putResults);
+        }
+
+        @Test
+        public void shouldPutObjectsWithoutTypeMappingAsObservable() {
+            final PutObjectsStub putStub = PutObjectsStub.newPutStubForMultipleObjectsWithoutTypeMapping();
+
+            final Observable<PutResults<TestItem>> observable = putStub.storIOContentResolver
+                    .put()
+                    .objects(putStub.items)
+                    .withPutResolver(putStub.putResolver)
+                    .prepare()
+                    .createObservable();
+
+            putStub.verifyBehaviorForMultipleObjects(observable);
+        }
+    }
+
+    public static class WithTypeMapping {
+
+        @Test
+        public void shouldPutObjectsWithTypeMappingBlocking() {
+            final PutObjectsStub putStub = PutObjectsStub.newPutStubForMultipleObjectsWithTypeMapping();
+
+            final PutResults<TestItem> putResults = putStub.storIOContentResolver
+                    .put()
+                    .objects(putStub.items)
+                    .prepare()
+                    .executeAsBlocking();
+
+            putStub.verifyBehaviorForMultipleObjects(putResults);
+        }
+
+        @Test
+        public void shouldPutObjectsWithTypeMappingAsObservable() {
+            final PutObjectsStub putStub = PutObjectsStub.newPutStubForMultipleObjectsWithTypeMapping();
+
+            final Observable<PutResults<TestItem>> observable = putStub.storIOContentResolver
+                    .put()
+                    .objects(putStub.items)
+                    .prepare()
+                    .createObservable();
+
+            putStub.verifyBehaviorForMultipleObjects(observable);
+        }
+    }
+
+    public static class NoTypeMappingError {
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderBlocking() {
+            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
+            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
+
+            when(storIOContentResolver.internal()).thenReturn(internal);
+
+            when(storIOContentResolver.put()).thenReturn(new PreparedPut.Builder(storIOContentResolver));
+
+            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
+
+            final PreparedPut<PutResults<TestItem>> preparedPut = storIOContentResolver
+                    .put()
+                    .objects(items)
+                    .prepare();
+
+            try {
+                preparedPut.executeAsBlocking();
+                fail();
+            } catch (IllegalStateException expected) {
+                // it's okay, no type mapping was found
+            }
+
+            verify(storIOContentResolver).put();
+            verify(storIOContentResolver).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
+            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
+            verifyNoMoreInteractions(storIOContentResolver, internal);
+        }
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderAsObservable() {
+            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
+            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
+
+            when(storIOContentResolver.internal()).thenReturn(internal);
+
+            when(storIOContentResolver.put()).thenReturn(new PreparedPut.Builder(storIOContentResolver));
+
+            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
+
+            final TestSubscriber<PutResults<TestItem>> testSubscriber = new TestSubscriber<PutResults<TestItem>>();
+
+            storIOContentResolver
+                    .put()
+                    .objects(items)
+                    .prepare()
+                    .createObservable()
+                    .subscribe(testSubscriber);
+
+            testSubscriber.awaitTerminalEvent();
+            testSubscriber.assertNoValues();
+            testSubscriber.assertError(IllegalStateException.class);
+
+            verify(storIOContentResolver).put();
+            verify(storIOContentResolver).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
+            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
+            verifyNoMoreInteractions(storIOContentResolver, internal);
+        }
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValuesIterableTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValuesIterableTest.java
new file mode 100644
index 0000000..0235b64
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValuesIterableTest.java
@@ -0,0 +1,38 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.content.ContentValues;
+
+import org.junit.Test;
+
+import rx.Observable;
+
+public class PreparedPutContentValuesIterableTest {
+
+    @Test
+    public void putContentValuesIterableBlocking() {
+        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForMultipleContentValues();
+
+        final PutResults<ContentValues> putResults = putStub.storIOContentResolver
+                .put()
+                .contentValues(putStub.contentValues)
+                .withPutResolver(putStub.putResolver)
+                .prepare()
+                .executeAsBlocking();
+
+        putStub.verifyBehaviorForMultipleContentValues(putResults);
+    }
+
+    @Test
+    public void putContentValuesIterableObservable() {
+        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForMultipleContentValues();
+
+        final Observable<PutResults<ContentValues>> putResultsObservable = putStub.storIOContentResolver
+                .put()
+                .contentValues(putStub.contentValues)
+                .withPutResolver(putStub.putResolver)
+                .prepare()
+                .createObservable();
+
+        putStub.verifyBehaviorForMultipleContentValues(putResultsObservable);
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValuesTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValuesTest.java
new file mode 100644
index 0000000..7e16482
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutContentValuesTest.java
@@ -0,0 +1,36 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import org.junit.Test;
+
+import rx.Observable;
+
+public class PreparedPutContentValuesTest {
+
+    @Test
+    public void putContentValuesBlocking() {
+        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForOneContentValues();
+
+        final PutResult putResult = putStub.storIOContentResolver
+                .put()
+                .contentValues(putStub.contentValues.get(0))
+                .withPutResolver(putStub.putResolver)
+                .prepare()
+                .executeAsBlocking();
+
+        putStub.verifyBehaviorForOneContentValues(putResult);
+    }
+
+    @Test
+    public void putContentValuesObservable() {
+        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForOneContentValues();
+
+        final Observable<PutResult> putResultObservable = putStub.storIOContentResolver
+                .put()
+                .contentValues(putStub.contentValues.get(0))
+                .withPutResolver(putStub.putResolver)
+                .prepare()
+                .createObservable();
+
+        putStub.verifyBehaviorForOneContentValues(putResultObservable);
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutObjectTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutObjectTest.java
new file mode 100644
index 0000000..f82fdf5
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PreparedPutObjectTest.java
@@ -0,0 +1,148 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.content.ContentValues;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;
+import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;
+
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import rx.Observable;
+import rx.observers.TestSubscriber;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(Enclosed.class)
+public class PreparedPutObjectTest {
+
+    public static class WithTypeMapping {
+
+        @Test
+        public void shouldPutObjectWithoutTypeMappingBlocking() {
+            final PutObjectsStub putStub = PutObjectsStub.newPutStubForOneObjectWithoutTypeMapping();
+
+            final PutResult putResult = putStub.storIOContentResolver
+                    .put()
+                    .object(putStub.items.get(0))
+                    .withPutResolver(putStub.putResolver)
+                    .prepare()
+                    .executeAsBlocking();
+
+            putStub.verifyBehaviorForOneObject(putResult);
+        }
+
+        @Test
+        public void shouldPutObjectWithoutTypeMappingAsObservable() {
+            final PutObjectsStub putStub = PutObjectsStub.newPutStubForOneObjectWithoutTypeMapping();
+
+            final Observable<PutResult> putResultObservable = putStub.storIOContentResolver
+                    .put()
+                    .object(putStub.items.get(0))
+                    .withPutResolver(putStub.putResolver)
+                    .prepare()
+                    .createObservable();
+
+            putStub.verifyBehaviorForOneObject(putResultObservable);
+        }
+    }
+
+    public static class WithoutTypeMapping {
+
+        @Test
+        public void shouldPutObjectWithTypeMappingBlocking() {
+            final PutObjectsStub putStub = PutObjectsStub.newPutStubForOneObjectWithTypeMapping();
+
+            final PutResult putResult = putStub.storIOContentResolver
+                    .put()
+                    .object(putStub.items.get(0))
+                    .prepare()
+                    .executeAsBlocking();
+
+            putStub.verifyBehaviorForOneObject(putResult);
+        }
+
+        @Test
+        public void shouldPutObjectWithTypeMappingAsObservable() {
+            final PutObjectsStub putStub = PutObjectsStub.newPutStubForOneObjectWithTypeMapping();
+
+            final Observable<PutResult> putResultObservable = putStub.storIOContentResolver
+                    .put()
+                    .object(putStub.items.get(0))
+                    .prepare()
+                    .createObservable();
+
+            putStub.verifyBehaviorForOneObject(putResultObservable);
+        }
+    }
+
+    public static class NoTypeMappingError {
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderBlocking() {
+            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
+            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
+
+            when(storIOContentResolver.internal()).thenReturn(internal);
+
+            when(storIOContentResolver.put()).thenReturn(new PreparedPut.Builder(storIOContentResolver));
+
+            final PreparedPut<PutResult> preparedPut = storIOContentResolver
+                    .put()
+                    .object(TestItem.newInstance())
+                    .prepare();
+
+            try {
+                preparedPut.executeAsBlocking();
+                fail();
+            } catch (IllegalStateException expected) {
+                // it's okay, no type mapping was found
+            }
+
+            verify(storIOContentResolver).put();
+            verify(storIOContentResolver).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
+            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
+            verifyNoMoreInteractions(storIOContentResolver, internal);
+        }
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingContentProviderAsObservable() {
+            final StorIOContentResolver storIOContentResolver = mock(StorIOContentResolver.class);
+            final StorIOContentResolver.Internal internal = mock(StorIOContentResolver.Internal.class);
+
+            when(storIOContentResolver.internal()).thenReturn(internal);
+
+            when(storIOContentResolver.put()).thenReturn(new PreparedPut.Builder(storIOContentResolver));
+
+            final TestSubscriber<PutResult> testSubscriber = new TestSubscriber<PutResult>();
+
+            storIOContentResolver
+                    .put()
+                    .object(TestItem.newInstance())
+                    .prepare()
+                    .createObservable()
+                    .subscribe(testSubscriber);
+
+            testSubscriber.awaitTerminalEvent();
+            testSubscriber.assertNoValues();
+            testSubscriber.assertError(IllegalStateException.class);
+
+            verify(storIOContentResolver).put();
+            verify(storIOContentResolver).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
+            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
+            verifyNoMoreInteractions(storIOContentResolver, internal);
+        }
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PutContentValuesStub.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PutContentValuesStub.java
new file mode 100644
index 0000000..1ddbe15
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PutContentValuesStub.java
@@ -0,0 +1,132 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.content.ContentValues;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import rx.Observable;
+import rx.functions.Action1;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+// stub class to avoid violation of DRY in tests
+class PutContentValuesStub {
+
+    @NonNull
+    final StorIOContentResolver storIOContentResolver;
+
+    @NonNull
+    private final StorIOContentResolver.Internal internal;
+
+    @NonNull
+    final List<ContentValues> contentValues;
+
+    @NonNull
+    final PutResolver<ContentValues> putResolver;
+
+    @NonNull
+    private final Map<ContentValues, PutResult> contentValuesToPutResultsMap;
+
+    @SuppressWarnings("unchecked")
+    private PutContentValuesStub(int numberOfTestItems) {
+        storIOContentResolver = mock(StorIOContentResolver.class);
+        internal = mock(StorIOContentResolver.Internal.class);
+
+        when(storIOContentResolver.internal())
+                .thenReturn(internal);
+
+        when(storIOContentResolver.put())
+                .thenReturn(new PreparedPut.Builder(storIOContentResolver));
+
+        contentValues = new ArrayList<ContentValues>(numberOfTestItems);
+        contentValuesToPutResultsMap = new HashMap<ContentValues, PutResult>(numberOfTestItems);
+
+        for (int i = 0; i < numberOfTestItems; i++) {
+            final ContentValues cv = mock(ContentValues.class);
+            contentValues.add(cv);
+            contentValuesToPutResultsMap.put(cv, PutResult.newInsertResult(mock(Uri.class), TestItem.CONTENT_URI));
+        }
+
+        putResolver = (PutResolver<ContentValues>) mock(PutResolver.class);
+
+        when(putResolver.performPut(eq(storIOContentResolver), any(ContentValues.class)))
+                .thenReturn(PutResult.newInsertResult(mock(Uri.class), TestItem.CONTENT_URI));
+
+        for (final ContentValues cv : contentValues) {
+            final PutResult putResult = PutResult.newInsertResult(mock(Uri.class), mock(Uri.class));
+
+            contentValuesToPutResultsMap.put(cv, putResult);
+
+            when(putResolver.performPut(storIOContentResolver, cv))
+                    .thenReturn(putResult);
+        }
+    }
+
+    @NonNull
+    public static PutContentValuesStub newPutStubForOneContentValues() {
+        return new PutContentValuesStub(1);
+    }
+
+    @NonNull
+    public static PutContentValuesStub newPutStubForMultipleContentValues() {
+        return new PutContentValuesStub(3);
+    }
+
+    void verifyBehaviorForMultipleContentValues(@NonNull PutResults<ContentValues> putResults) {
+        // only one call to storIOContentResolver.put() should occur
+        verify(storIOContentResolver, times(1)).put();
+
+        // number of calls to putResolver's performPut() should be equal to number of objects
+        verify(putResolver, times(contentValues.size())).performPut(eq(storIOContentResolver), any(ContentValues.class));
+
+        for (final ContentValues cv : contentValues) {
+            // Put Operation should be performed once for each item
+            verify(putResolver, times(1)).performPut(storIOContentResolver, cv);
+        }
+    }
+
+    void verifyBehaviorForMultipleContentValues(@NonNull Observable<PutResults<ContentValues>> putResultsObservable) {
+        new ObservableBehaviorChecker<PutResults<ContentValues>>()
+                .observable(putResultsObservable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<PutResults<ContentValues>>() {
+                    @Override
+                    public void call(PutResults<ContentValues> putResults) {
+                        verifyBehaviorForMultipleContentValues(putResults);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+
+    void verifyBehaviorForOneContentValues(@NonNull PutResult putResult) {
+        Map<ContentValues, PutResult> putResultsMap = new HashMap<ContentValues, PutResult>(1);
+        putResultsMap.put(contentValues.get(0), putResult);
+        verifyBehaviorForMultipleContentValues(PutResults.newInstance(putResultsMap));
+    }
+
+    void verifyBehaviorForOneContentValues(@NonNull Observable<PutResult> putResultObservable) {
+        new ObservableBehaviorChecker<PutResult>()
+                .observable(putResultObservable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<PutResult>() {
+                    @Override
+                    public void call(PutResult putResult) {
+                        verifyBehaviorForOneContentValues(putResult);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PutObjectsStub.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PutObjectsStub.java
new file mode 100644
index 0000000..42c9822
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/PutObjectsStub.java
@@ -0,0 +1,173 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
+import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
+import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import rx.Observable;
+import rx.functions.Action1;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+// stub class to avoid violation of DRY in tests
+class PutObjectsStub {
+
+    @NonNull
+    final StorIOContentResolver storIOContentResolver;
+
+    @NonNull
+    private final StorIOContentResolver.Internal internal;
+
+    @NonNull
+    final List<TestItem> items;
+
+    @NonNull
+    final PutResolver<TestItem> putResolver;
+
+    @NonNull
+    private final ContentResolverTypeMapping<TestItem> typeMapping;
+
+    @NonNull
+    private final Map<TestItem, PutResult> itemsToPutResultsMap;
+
+    private final boolean withTypeMapping;
+
+    @SuppressWarnings("unchecked")
+    private PutObjectsStub(boolean withTypeMapping, int numberOfTestItems) {
+        this.withTypeMapping = withTypeMapping;
+
+        storIOContentResolver = mock(StorIOContentResolver.class);
+        internal = mock(StorIOContentResolver.Internal.class);
+
+        when(storIOContentResolver.internal())
+                .thenReturn(internal);
+
+        when(storIOContentResolver.put())
+                .thenReturn(new PreparedPut.Builder(storIOContentResolver));
+
+        items = new ArrayList<TestItem>(numberOfTestItems);
+
+        for (int i = 0; i < numberOfTestItems; i++) {
+            final TestItem testItem = TestItem.newInstance();
+            items.add(testItem);
+        }
+
+        putResolver = (PutResolver<TestItem>) mock(PutResolver.class);
+        itemsToPutResultsMap = new HashMap<TestItem, PutResult>(numberOfTestItems);
+
+        for (final TestItem testItem : items) {
+            final PutResult putResult = PutResult.newInsertResult(mock(Uri.class), mock(Uri.class));
+            itemsToPutResultsMap.put(testItem, putResult);
+
+            when(putResolver.performPut(storIOContentResolver, testItem))
+                    .thenReturn(putResult);
+        }
+
+        typeMapping = mock(ContentResolverTypeMapping.class);
+
+        if (withTypeMapping) {
+            when(internal.typeMapping(TestItem.class)).thenReturn(typeMapping);
+            when(typeMapping.putResolver()).thenReturn(putResolver);
+        }
+    }
+
+    @NonNull
+    public static PutObjectsStub newPutStubForOneObjectWithoutTypeMapping() {
+        return new PutObjectsStub(false, 1);
+    }
+
+    @NonNull
+    public static PutObjectsStub newPutStubForOneObjectWithTypeMapping() {
+        return new PutObjectsStub(true, 1);
+    }
+
+    @NonNull
+    public static PutObjectsStub newPutStubForMultipleObjectsWithoutTypeMapping() {
+        return new PutObjectsStub(false, 3);
+    }
+
+    @NonNull
+    public static PutObjectsStub newPutStubForMultipleObjectsWithTypeMapping() {
+        return new PutObjectsStub(true, 3);
+    }
+
+    void verifyBehaviorForMultipleObjects(@NonNull PutResults<TestItem> putResults) {
+        if (items.size() > 1 || withTypeMapping) {
+            // should be called only once because of Performance!
+            verify(storIOContentResolver).internal();
+        } else {
+            verify(storIOContentResolver, never()).internal();
+        }
+
+        // should be called only once
+        verify(storIOContentResolver).put();
+
+        // number of calls to putResolver's performPut() should be equal to number of objects
+        verify(putResolver, times(items.size())).performPut(eq(storIOContentResolver), any(TestItem.class));
+
+        for (final TestItem testItem : items) {
+            // checks that put was performed for each item
+            verify(putResolver, times(1)).performPut(storIOContentResolver, testItem);
+
+            final PutResult expectedPutResult = itemsToPutResultsMap.get(testItem);
+            assertEquals(expectedPutResult, putResults.results().get(testItem));
+        }
+
+        assertEquals(itemsToPutResultsMap.size(), putResults.results().size());
+
+        if (withTypeMapping) {
+            verify(internal, times(items.size())).typeMapping(TestItem.class);
+            verify(typeMapping, times(items.size())).putResolver();
+        }
+
+        verifyNoMoreInteractions(storIOContentResolver, internal, typeMapping, putResolver);
+    }
+
+    void verifyBehaviorForMultipleObjects(@NonNull Observable<PutResults<TestItem>> putResultsObservable) {
+        new ObservableBehaviorChecker<PutResults<TestItem>>()
+                .observable(putResultsObservable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<PutResults<TestItem>>() {
+                    @Override
+                    public void call(PutResults<TestItem> putResults) {
+                        verifyBehaviorForMultipleObjects(putResults);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+
+    void verifyBehaviorForOneObject(@NonNull PutResult putResult) {
+        Map<TestItem, PutResult> putResultsMap = new HashMap<TestItem, PutResult>(1);
+        putResultsMap.put(items.get(0), putResult);
+        verifyBehaviorForMultipleObjects(PutResults.newInstance(putResultsMap));
+    }
+
+    void verifyBehaviorForOneObject(@NonNull Observable<PutResult> putResultObservable) {
+        new ObservableBehaviorChecker<PutResult>()
+                .observable(putResultObservable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<PutResult>() {
+                    @Override
+                    public void call(PutResult putResult) {
+                        verifyBehaviorForOneObject(putResult);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/TestItem.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/TestItem.java
new file mode 100644
index 0000000..1135b1c
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/operations/put/TestItem.java
@@ -0,0 +1,19 @@
+package com.pushtorefresh.storio.contentresolver.operations.put;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import static org.mockito.Mockito.mock;
+
+class TestItem {
+    static final Uri CONTENT_URI = mock(Uri.class);
+
+    private TestItem() {
+
+    }
+
+    @NonNull
+    static TestItem newInstance() {
+        return new TestItem();
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/DeleteQueryTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/DeleteQueryTest.java
new file mode 100644
index 0000000..f195d76
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/DeleteQueryTest.java
@@ -0,0 +1,77 @@
+package com.pushtorefresh.storio.contentresolver.queries;
+
+import android.net.Uri;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+public class DeleteQueryTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void shouldNotAllowNullUriObject() {
+        DeleteQuery.builder()
+                .uri((Uri) null) // LOL, via overload we disabled null uri without specifying Type!
+                .build();
+    }
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class) // Uri#parse() not mocked
+    public void shouldNotAllowNullUriString() {
+        DeleteQuery.builder()
+                .uri((String) null)
+                .build();
+    }
+
+    @Test
+    public void whereClauseShouldNotBeNull() {
+        DeleteQuery deleteQuery = DeleteQuery.builder()
+                .uri(mock(Uri.class))
+                .where(null)
+                .build();
+
+        assertEquals("", deleteQuery.where());
+    }
+
+    @Test
+    public void whereArgsShouldNotBeNull() {
+        DeleteQuery deleteQuery = DeleteQuery.builder()
+                .uri(mock(Uri.class))
+                .where("c1 = s")
+                .build();
+
+        assertNotNull(deleteQuery.whereArgs());
+        assertTrue(deleteQuery.whereArgs().isEmpty());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void shouldThrowExceptionIfWhereArgsSpecifiedWithoutWhereClause() {
+        DeleteQuery.builder()
+                .uri(mock(Uri.class))
+                .whereArgs("someArg") // Without WHERE clause!
+                .build();
+    }
+
+    @Test
+    public void buildWithNormalValues() {
+        final Uri uri = mock(Uri.class);
+        final String where = "test_where";
+        final Object[] whereArgs = {"arg1", "arg2", "arg3"};
+
+        final DeleteQuery deleteQuery = DeleteQuery.builder()
+                .uri(uri)
+                .where(where)
+                .whereArgs(whereArgs)
+                .build();
+
+        assertEquals(uri, deleteQuery.uri());
+        assertEquals(where, deleteQuery.where());
+        assertEquals(Arrays.asList(whereArgs), deleteQuery.whereArgs());
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/InsertQueryTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/InsertQueryTest.java
new file mode 100644
index 0000000..105e5a8
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/InsertQueryTest.java
@@ -0,0 +1,38 @@
+package com.pushtorefresh.storio.contentresolver.queries;
+
+import android.net.Uri;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+public class InsertQueryTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void shouldNotAllowNullUriObject() {
+        InsertQuery.builder()
+                .uri((Uri) null)
+                .build();
+    }
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void shouldNotAllowNullUriString() {
+        InsertQuery.builder()
+                .uri((String) null)
+                .build();
+    }
+
+    @Test
+    public void buildWithNormalValues() {
+        final Uri uri = mock(Uri.class);
+
+        final InsertQuery insertQuery = InsertQuery.builder()
+                .uri(uri)
+                .build();
+
+        assertEquals(uri, insertQuery.uri());
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/QueryTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/QueryTest.java
new file mode 100644
index 0000000..db9a05f
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/QueryTest.java
@@ -0,0 +1,93 @@
+package com.pushtorefresh.storio.contentresolver.queries;
+
+import android.net.Uri;
+
+import org.junit.Test;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+public class QueryTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void shouldNotAllowNullUriObject() {
+        Query.builder()
+                .uri((Uri) null)
+                .build();
+    }
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void shouldNotAllowNullUriString() {
+        Query.builder()
+                .uri((String) null)
+                .build();
+    }
+
+    @Test
+    public void columnsShouldNotBeNull() {
+        Query query = Query.builder()
+                .uri(mock(Uri.class))
+                .build();
+
+        assertNotNull(query.columns());
+        assertTrue(query.columns().isEmpty());
+    }
+
+    @Test
+    public void whereClauseShouldNotBeNull() {
+        Query query = Query.builder()
+                .uri(mock(Uri.class))
+                .build();
+
+        assertNotNull(query.where());
+        assertEquals("", query.where());
+    }
+
+    @Test
+    public void whereArgsShouldNotBeNull() {
+        Query query = Query.builder()
+                .uri(mock(Uri.class))
+                .build();
+
+        assertNotNull(query.whereArgs());
+        assertTrue(query.whereArgs().isEmpty());
+    }
+
+    @Test
+    public void sortOrderShouldNotBeNull() {
+        Query query = Query.builder()
+                .uri(mock(Uri.class))
+                .build();
+
+        assertNotNull(query.sortOrder());
+        assertEquals("", query.sortOrder());
+    }
+
+    @Test
+    public void buildWithNormalValues() {
+        final Uri uri = mock(Uri.class);
+        final String[] columns = {"1", "2", "3"};
+        final String where = "test_where";
+        final Object[] whereArgs = {"arg1", "arg2", "arg3"};
+        final String sortOrder = "test_order";
+
+        final Query query = Query.builder()
+                .uri(uri)
+                .columns(columns)
+                .where(where)
+                .whereArgs(whereArgs)
+                .sortOrder(sortOrder)
+                .build();
+
+        assertEquals(uri, query.uri());
+        assertEquals(asList(columns), query.columns());
+        assertEquals(where, query.where());
+        assertEquals(asList(whereArgs), query.whereArgs());
+        assertEquals(sortOrder, query.sortOrder());
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/UpdateQueryTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/UpdateQueryTest.java
new file mode 100644
index 0000000..fe15cd3
--- /dev/null
+++ b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/queries/UpdateQueryTest.java
@@ -0,0 +1,75 @@
+package com.pushtorefresh.storio.contentresolver.queries;
+
+import android.net.Uri;
+
+import org.junit.Test;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+public class UpdateQueryTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void shouldNotAllowNullUriObject() {
+        UpdateQuery.builder()
+                .uri((Uri) null)
+                .build();
+    }
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void shouldNotAllowNullUriString() {
+        UpdateQuery.builder()
+                .uri((String) null)
+                .build();
+    }
+
+    @Test
+    public void whereClauseShouldNotBeNull() {
+        UpdateQuery updateQuery = UpdateQuery.builder()
+                .uri(mock(Uri.class))
+                .build();
+
+        assertNotNull(updateQuery.where());
+        assertEquals("", updateQuery.where());
+    }
+
+    @Test
+    public void whereArgsShouldNotBeNull() {
+        UpdateQuery updateQuery = UpdateQuery.builder()
+                .uri(mock(Uri.class))
+                .build();
+
+        assertNotNull(updateQuery.whereArgs());
+        assertTrue(updateQuery.whereArgs().isEmpty());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void shouldThrowExceptionIfWhereArgsSpecifiedWithoutWhereClause() {
+        UpdateQuery.builder()
+                .uri(mock(Uri.class))
+                .whereArgs("someArg") // Without WHERE clause!
+                .build();
+    }
+
+    @Test
+    public void buildWithNormalValues() {
+        final Uri uri = mock(Uri.class);
+        final String where = "test_where";
+        final Object[] whereArgs = {"arg1", "arg2", "arg3"};
+
+        final UpdateQuery updateQuery = UpdateQuery.builder()
+                .uri(uri)
+                .where(where)
+                .whereArgs(whereArgs)
+                .build();
+
+        assertEquals(uri, updateQuery.uri());
+        assertEquals(where, updateQuery.where());
+        assertEquals(asList(whereArgs), updateQuery.whereArgs());
+    }
+}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/DeleteQueryTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/DeleteQueryTest.java
deleted file mode 100644
index f7117aa..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/DeleteQueryTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.query;
-
-import android.net.Uri;
-
-import org.junit.Test;
-
-import java.util.Arrays;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-public class DeleteQueryTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void shouldNotAllowNullUriObject() {
-        DeleteQuery.builder()
-                .uri((Uri) null) // LOL, via overload we disabled null uri without specifying Type!
-                .build();
-    }
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class) // Uri#parse() not mocked
-    public void shouldNotAllowNullUriString() {
-        DeleteQuery.builder()
-                .uri((String) null)
-                .build();
-    }
-
-    @Test
-    public void whereClauseShouldNotBeNull() {
-        DeleteQuery deleteQuery = DeleteQuery.builder()
-                .uri(mock(Uri.class))
-                .where(null)
-                .build();
-
-        assertEquals("", deleteQuery.where());
-    }
-
-    @Test
-    public void whereArgsShouldNotBeNull() {
-        DeleteQuery deleteQuery = DeleteQuery.builder()
-                .uri(mock(Uri.class))
-                .where("c1 = s")
-                .build();
-
-        assertNotNull(deleteQuery.whereArgs());
-        assertTrue(deleteQuery.whereArgs().isEmpty());
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void shouldThrowExceptionIfWhereArgsSpecifiedWithoutWhereClause() {
-        DeleteQuery.builder()
-                .uri(mock(Uri.class))
-                .whereArgs("someArg") // Without WHERE clause!
-                .build();
-    }
-
-    @Test
-    public void buildWithNormalValues() {
-        final Uri uri = mock(Uri.class);
-        final String where = "test_where";
-        final Object[] whereArgs = {"arg1", "arg2", "arg3"};
-
-        final DeleteQuery deleteQuery = DeleteQuery.builder()
-                .uri(uri)
-                .where(where)
-                .whereArgs(whereArgs)
-                .build();
-
-        assertEquals(uri, deleteQuery.uri());
-        assertEquals(where, deleteQuery.where());
-        assertEquals(Arrays.asList(whereArgs), deleteQuery.whereArgs());
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/InsertQueryTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/InsertQueryTest.java
deleted file mode 100644
index 83ffefd..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/InsertQueryTest.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.query;
-
-import android.net.Uri;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-
-public class InsertQueryTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void shouldNotAllowNullUriObject() {
-        InsertQuery.builder()
-                .uri((Uri) null)
-                .build();
-    }
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void shouldNotAllowNullUriString() {
-        InsertQuery.builder()
-                .uri((String) null)
-                .build();
-    }
-
-    @Test
-    public void buildWithNormalValues() {
-        final Uri uri = mock(Uri.class);
-
-        final InsertQuery insertQuery = InsertQuery.builder()
-                .uri(uri)
-                .build();
-
-        assertEquals(uri, insertQuery.uri());
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/QueryTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/QueryTest.java
deleted file mode 100644
index 0dbb68a..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/QueryTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.query;
-
-import android.net.Uri;
-
-import org.junit.Test;
-
-import static java.util.Arrays.asList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-public class QueryTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void shouldNotAllowNullUriObject() {
-        Query.builder()
-                .uri((Uri) null)
-                .build();
-    }
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void shouldNotAllowNullUriString() {
-        Query.builder()
-                .uri((String) null)
-                .build();
-    }
-
-    @Test
-    public void columnsShouldNotBeNull() {
-        Query query = Query.builder()
-                .uri(mock(Uri.class))
-                .build();
-
-        assertNotNull(query.columns());
-        assertTrue(query.columns().isEmpty());
-    }
-
-    @Test
-    public void whereClauseShouldNotBeNull() {
-        Query query = Query.builder()
-                .uri(mock(Uri.class))
-                .build();
-
-        assertNotNull(query.where());
-        assertEquals("", query.where());
-    }
-
-    @Test
-    public void whereArgsShouldNotBeNull() {
-        Query query = Query.builder()
-                .uri(mock(Uri.class))
-                .build();
-
-        assertNotNull(query.whereArgs());
-        assertTrue(query.whereArgs().isEmpty());
-    }
-
-    @Test
-    public void sortOrderShouldNotBeNull() {
-        Query query = Query.builder()
-                .uri(mock(Uri.class))
-                .build();
-
-        assertNotNull(query.sortOrder());
-        assertEquals("", query.sortOrder());
-    }
-
-    @Test
-    public void buildWithNormalValues() {
-        final Uri uri = mock(Uri.class);
-        final String[] columns = {"1", "2", "3"};
-        final String where = "test_where";
-        final Object[] whereArgs = {"arg1", "arg2", "arg3"};
-        final String sortOrder = "test_order";
-
-        final Query query = Query.builder()
-                .uri(uri)
-                .columns(columns)
-                .where(where)
-                .whereArgs(whereArgs)
-                .sortOrder(sortOrder)
-                .build();
-
-        assertEquals(uri, query.uri());
-        assertEquals(asList(columns), query.columns());
-        assertEquals(where, query.where());
-        assertEquals(asList(whereArgs), query.whereArgs());
-        assertEquals(sortOrder, query.sortOrder());
-    }
-}
diff --git a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/UpdateQueryTest.java b/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/UpdateQueryTest.java
deleted file mode 100644
index c278a54..0000000
--- a/storio-content-resolver/src/test/java/com/pushtorefresh/storio/contentresolver/query/UpdateQueryTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package com.pushtorefresh.storio.contentresolver.query;
-
-import android.net.Uri;
-
-import org.junit.Test;
-
-import static java.util.Arrays.asList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-public class UpdateQueryTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void shouldNotAllowNullUriObject() {
-        UpdateQuery.builder()
-                .uri((Uri) null)
-                .build();
-    }
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void shouldNotAllowNullUriString() {
-        UpdateQuery.builder()
-                .uri((String) null)
-                .build();
-    }
-
-    @Test
-    public void whereClauseShouldNotBeNull() {
-        UpdateQuery updateQuery = UpdateQuery.builder()
-                .uri(mock(Uri.class))
-                .build();
-
-        assertNotNull(updateQuery.where());
-        assertEquals("", updateQuery.where());
-    }
-
-    @Test
-    public void whereArgsShouldNotBeNull() {
-        UpdateQuery updateQuery = UpdateQuery.builder()
-                .uri(mock(Uri.class))
-                .build();
-
-        assertNotNull(updateQuery.whereArgs());
-        assertTrue(updateQuery.whereArgs().isEmpty());
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void shouldThrowExceptionIfWhereArgsSpecifiedWithoutWhereClause() {
-        UpdateQuery.builder()
-                .uri(mock(Uri.class))
-                .whereArgs("someArg") // Without WHERE clause!
-                .build();
-    }
-
-    @Test
-    public void buildWithNormalValues() {
-        final Uri uri = mock(Uri.class);
-        final String where = "test_where";
-        final Object[] whereArgs = {"arg1", "arg2", "arg3"};
-
-        final UpdateQuery updateQuery = UpdateQuery.builder()
-                .uri(uri)
-                .where(where)
-                .whereArgs(whereArgs)
-                .build();
-
-        assertEquals(uri, updateQuery.uri());
-        assertEquals(where, updateQuery.where());
-        assertEquals(asList(whereArgs), updateQuery.whereArgs());
-    }
-}
diff --git a/storio-sample-app/src/androidTest/java/com/pushtorefresh/storio/contentresolver/test/BaseTest.java b/storio-sample-app/src/androidTest/java/com/pushtorefresh/storio/contentresolver/test/BaseTest.java
index 57cfb42..af6d7e9 100644
--- a/storio-sample-app/src/androidTest/java/com/pushtorefresh/storio/contentresolver/test/BaseTest.java
+++ b/storio-sample-app/src/androidTest/java/com/pushtorefresh/storio/contentresolver/test/BaseTest.java
@@ -6,7 +6,7 @@
 import com.pushtorefresh.storio.contentresolver.ContentResolverTypeMapping;
 import com.pushtorefresh.storio.contentresolver.StorIOContentResolver;
 import com.pushtorefresh.storio.contentresolver.impl.DefaultStorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
 import com.pushtorefresh.storio.sample.db.entity.Tweet;
 import com.pushtorefresh.storio.sample.provider.meta.TweetMeta;
 
diff --git a/storio-sample-app/src/androidTest/java/com/pushtorefresh/storio/contentresolver/test/ObserveChangesTest.java b/storio-sample-app/src/androidTest/java/com/pushtorefresh/storio/contentresolver/test/ObserveChangesTest.java
index 8ab5d34..1b71be4 100644
--- a/storio-sample-app/src/androidTest/java/com/pushtorefresh/storio/contentresolver/test/ObserveChangesTest.java
+++ b/storio-sample-app/src/androidTest/java/com/pushtorefresh/storio/contentresolver/test/ObserveChangesTest.java
@@ -4,8 +4,8 @@
 import android.support.test.runner.AndroidJUnit4;
 
 import com.pushtorefresh.storio.contentresolver.Changes;
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResult;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResult;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResult;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResult;
 import com.pushtorefresh.storio.sample.db.entity.Tweet;
 import com.pushtorefresh.storio.sample.provider.meta.TweetMeta;
 import com.pushtorefresh.storio.test.AbstractEmissionChecker;
diff --git a/storio-sample-app/src/androidTest/java/com/pushtorefresh/storio/contentresolver/test/RxQueryTest.java b/storio-sample-app/src/androidTest/java/com/pushtorefresh/storio/contentresolver/test/RxQueryTest.java
index c5f6eda..dc65b47 100644
--- a/storio-sample-app/src/androidTest/java/com/pushtorefresh/storio/contentresolver/test/RxQueryTest.java
+++ b/storio-sample-app/src/androidTest/java/com/pushtorefresh/storio/contentresolver/test/RxQueryTest.java
@@ -3,9 +3,9 @@
 import android.support.annotation.NonNull;
 import android.support.test.runner.AndroidJUnit4;
 
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResult;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResult;
-import com.pushtorefresh.storio.contentresolver.query.Query;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResult;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResult;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
 import com.pushtorefresh.storio.sample.db.entity.Tweet;
 import com.pushtorefresh.storio.sample.provider.meta.TweetMeta;
 import com.pushtorefresh.storio.test.AbstractEmissionChecker;
diff --git a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/entity/Tweet.java b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/entity/Tweet.java
index 6efeadb..c047a5a 100644
--- a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/entity/Tweet.java
+++ b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/entity/Tweet.java
@@ -3,8 +3,8 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
-import com.pushtorefresh.storio.sqlite.annotation.StorIOSQLiteColumn;
-import com.pushtorefresh.storio.sqlite.annotation.StorIOSQLiteType;
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn;
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType;
 
 /**
  * Just for demonstration, real Tweet structure is more complex
diff --git a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/table/TweetTableMeta.java b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/table/TweetTableMeta.java
index d114c14..e780a4a 100644
--- a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/table/TweetTableMeta.java
+++ b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/db/table/TweetTableMeta.java
@@ -5,16 +5,16 @@
 import android.support.annotation.NonNull;
 
 import com.pushtorefresh.storio.sample.db.entity.Tweet;
-import com.pushtorefresh.storio.sqlite.operation.delete.DefaultDeleteResolver;
-import com.pushtorefresh.storio.sqlite.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.sqlite.operation.get.DefaultGetResolver;
-import com.pushtorefresh.storio.sqlite.operation.get.GetResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.DefaultPutResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResolver;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-import com.pushtorefresh.storio.sqlite.query.InsertQuery;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.UpdateQuery;
+import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver;
+import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver;
+import com.pushtorefresh.storio.sqlite.operations.get.GetResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResolver;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+import com.pushtorefresh.storio.sqlite.queries.InsertQuery;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.UpdateQuery;
 
 public class TweetTableMeta {
 
diff --git a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/provider/meta/TweetMeta.java b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/provider/meta/TweetMeta.java
index dd6814f..da1117e 100644
--- a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/provider/meta/TweetMeta.java
+++ b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/provider/meta/TweetMeta.java
@@ -5,15 +5,15 @@
 import android.net.Uri;
 import android.support.annotation.NonNull;
 
-import com.pushtorefresh.storio.contentresolver.operation.delete.DefaultDeleteResolver;
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.contentresolver.operation.get.DefaultGetResolver;
-import com.pushtorefresh.storio.contentresolver.operation.get.GetResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.DefaultPutResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResolver;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-import com.pushtorefresh.storio.contentresolver.query.InsertQuery;
-import com.pushtorefresh.storio.contentresolver.query.UpdateQuery;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DefaultDeleteResolver;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.contentresolver.operations.get.DefaultGetResolver;
+import com.pushtorefresh.storio.contentresolver.operations.get.GetResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.DefaultPutResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResolver;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+import com.pushtorefresh.storio.contentresolver.queries.InsertQuery;
+import com.pushtorefresh.storio.contentresolver.queries.UpdateQuery;
 import com.pushtorefresh.storio.sample.db.entity.Tweet;
 import com.pushtorefresh.storio.sample.db.table.TweetTableMeta;
 import com.pushtorefresh.storio.sample.provider.SampleContentProvider;
diff --git a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/ui/fragment/TweetsFragment.java b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/ui/fragment/TweetsFragment.java
index 3d17d8d..dd374f9 100644
--- a/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/ui/fragment/TweetsFragment.java
+++ b/storio-sample-app/src/main/java/com/pushtorefresh/storio/sample/ui/fragment/TweetsFragment.java
@@ -19,7 +19,7 @@
 import com.pushtorefresh.storio.sample.ui.UiStateController;
 import com.pushtorefresh.storio.sample.ui.adapter.TweetsAdapter;
 import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResults;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResults;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/storio-sqlite-annotation-processor/build.gradle b/storio-sqlite-annotation-processor/build.gradle
deleted file mode 100644
index 72da066..0000000
--- a/storio-sqlite-annotation-processor/build.gradle
+++ /dev/null
@@ -1,16 +0,0 @@
-apply plugin: 'java'
-
-targetCompatibility = '1.6'
-sourceCompatibility = '1.6'
-
-dependencies {
-    compile libraries.storIOSQLiteAnnotation
-    compile libraries.intellijAnnotations
-    compile libraries.autoService
-    compile libraries.javaPoet
-
-    testCompile libraries.junit
-    testCompile libraries.mockitoCore
-}
-
-apply from: '../gradle/publish-java-lib.gradle'
\ No newline at end of file
diff --git a/storio-sqlite-annotation-processor/gradle.properties b/storio-sqlite-annotation-processor/gradle.properties
deleted file mode 100644
index 60dfef6..0000000
--- a/storio-sqlite-annotation-processor/gradle.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-POM_NAME=sqlite-annotation-processor
-POM_ARTIFACT_ID=sqlite-annotation-processor
-POM_PACKAGING=jar
\ No newline at end of file
diff --git a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/ProcessingException.java b/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/ProcessingException.java
deleted file mode 100644
index e9c04ca..0000000
--- a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/ProcessingException.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor;
-
-import org.jetbrains.annotations.NotNull;
-
-import javax.lang.model.element.Element;
-
-/**
- * Useful for logging errors from AnnotationProcessor,
- * stores reference to {@link Element} that caused exception so IDE will show developer where is the problem
- */
-public class ProcessingException extends RuntimeException {
-
-    /**
-     * Element that caused exception
-     */
-    @NotNull
-    private final Element element;
-
-    public ProcessingException(@NotNull Element element, @NotNull String message) {
-        super(message);
-        this.element = element;
-    }
-
-    /**
-     * @return non-null element that caused exception
-     */
-    @NotNull
-    public Element element() {
-        return element;
-    }
-}
diff --git a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/StorIOSQLiteProcessor.java b/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/StorIOSQLiteProcessor.java
deleted file mode 100644
index bf48438..0000000
--- a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/StorIOSQLiteProcessor.java
+++ /dev/null
@@ -1,331 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor;
-
-import com.google.auto.service.AutoService;
-import com.pushtorefresh.storio.sqlite.annotation.StorIOSQLiteColumn;
-import com.pushtorefresh.storio.sqlite.annotation.StorIOSQLiteType;
-import com.pushtorefresh.storio.sqlite.processor.generate.DeleteResolverGenerator;
-import com.pushtorefresh.storio.sqlite.processor.generate.GetResolverGenerator;
-import com.pushtorefresh.storio.sqlite.processor.generate.PutResolverGenerator;
-import com.pushtorefresh.storio.sqlite.processor.introspection.JavaType;
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteColumnMeta;
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteTypeMeta;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.Filer;
-import javax.annotation.processing.Messager;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.annotation.processing.Processor;
-import javax.annotation.processing.RoundEnvironment;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.Elements;
-
-import static javax.lang.model.element.ElementKind.CLASS;
-import static javax.lang.model.element.Modifier.FINAL;
-import static javax.lang.model.element.Modifier.PRIVATE;
-import static javax.tools.Diagnostic.Kind.ERROR;
-
-/**
- * Annotation processor for StorIOSQLite
- * <p>
- * It'll process annotations to generate StorIOSQLite Object-Mapping
- * <p>
- * Addition: Annotation Processor should work fast and be optimized because it's part of compilation
- * We don't want to annoy developers, who use StorIO
- */
-// Generate file with annotation processor declaration via another Annotation Processor!
-@AutoService(Processor.class)
-public class StorIOSQLiteProcessor extends AbstractProcessor {
-
-    private Filer filer;
-    private Elements elementUtils;
-    private Messager messager;
-
-    /**
-     * Processes class annotations
-     *
-     * @param roundEnvironment environment
-     * @return non-null unmodifiable map(element, typeMeta)
-     */
-    @NotNull
-    private static Map<TypeElement, StorIOSQLiteTypeMeta> processAnnotatedClasses(@NotNull final RoundEnvironment roundEnvironment, @NotNull final Elements elementUtils) {
-        final Set<? extends Element> elementsAnnotatedWithStorIOSQLiteType
-                = roundEnvironment.getElementsAnnotatedWith(StorIOSQLiteType.class);
-
-        final Map<TypeElement, StorIOSQLiteTypeMeta> results
-                = new HashMap<TypeElement, StorIOSQLiteTypeMeta>(elementsAnnotatedWithStorIOSQLiteType.size());
-
-        for (final Element annotatedElement : elementsAnnotatedWithStorIOSQLiteType) {
-            final TypeElement classElement = validateAnnotatedClass(annotatedElement);
-            final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = processAnnotatedClass(classElement, elementUtils);
-            results.put(classElement, storIOSQLiteTypeMeta);
-        }
-
-        return Collections.unmodifiableMap(results);
-    }
-
-    /**
-     * Checks that element annotated with {@link StorIOSQLiteType} satisfies all required conditions
-     *
-     * @param annotatedElement element annotated with {@link StorIOSQLiteType}
-     * @return {@link TypeElement} object
-     */
-    @NotNull
-    private static TypeElement validateAnnotatedClass(@NotNull final Element annotatedElement) {
-        // we expect here that annotatedElement is Class, annotation requires that via @Target
-        final TypeElement annotatedTypeElement = (TypeElement) annotatedElement;
-
-        if (annotatedTypeElement.getModifiers().contains(PRIVATE)) {
-            throw new ProcessingException(
-                    annotatedElement,
-                    StorIOSQLiteType.class.getSimpleName() + " can not be applied to private class: " + annotatedTypeElement.getQualifiedName()
-            );
-        }
-
-        return annotatedTypeElement;
-    }
-
-    /**
-     * Processes annotated class
-     *
-     * @param classElement type element annotated with {@link StorIOSQLiteType}
-     * @param elementUtils utils for working with elementUtils
-     * @return result of processing as {@link StorIOSQLiteTypeMeta}
-     */
-    @NotNull
-    private static StorIOSQLiteTypeMeta processAnnotatedClass(@NotNull TypeElement classElement, @NotNull Elements elementUtils) {
-        final StorIOSQLiteType storIOSQLiteType = classElement.getAnnotation(StorIOSQLiteType.class);
-
-        final String tableName = storIOSQLiteType.table();
-
-        if (tableName == null || tableName.length() == 0) {
-            throw new ProcessingException(
-                    classElement,
-                    "Table name of " + classElement.getQualifiedName() + " annotated with " + StorIOSQLiteType.class.getSimpleName() + " is null or empty"
-            );
-        }
-
-        final String simpleName = classElement.getSimpleName().toString();
-        final String packageName = elementUtils.getPackageOf(classElement).getQualifiedName().toString();
-
-        return new StorIOSQLiteTypeMeta(simpleName, packageName, storIOSQLiteType);
-    }
-
-    /**
-     * Processes fields annotated with {@link StorIOSQLiteColumn}
-     *
-     * @param roundEnvironment current processing environment
-     * @param annotatedClasses map of classes annotated with {@link StorIOSQLiteType}
-     */
-    private static void processAnnotatedFields(@NotNull final RoundEnvironment roundEnvironment, @NotNull Map<TypeElement, StorIOSQLiteTypeMeta> annotatedClasses) {
-        final Set<? extends Element> elementsAnnotatedWithStorIOSQLiteColumn
-                = roundEnvironment.getElementsAnnotatedWith(StorIOSQLiteColumn.class);
-
-        for (final Element annotatedFieldElement : elementsAnnotatedWithStorIOSQLiteColumn) {
-            validateAnnotatedField(annotatedFieldElement);
-            final StorIOSQLiteColumnMeta storIOSQLiteColumnMeta = processAnnotatedField(annotatedFieldElement);
-
-            final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = annotatedClasses.get(storIOSQLiteColumnMeta.enclosingElement);
-
-            if (storIOSQLiteTypeMeta == null) {
-                throw new ProcessingException(annotatedFieldElement, "Field marked with "
-                        + StorIOSQLiteColumn.class.getSimpleName()
-                        + " annotation should be placed in class marked by "
-                        + StorIOSQLiteType.class.getSimpleName()
-                        + " annotation"
-                );
-            }
-
-            // Put meta column info
-            // If class already contains column with same name -> throw exception
-            if (storIOSQLiteTypeMeta.columns.put(storIOSQLiteColumnMeta.storIOSQLiteColumn.name(), storIOSQLiteColumnMeta) != null) {
-                throw new ProcessingException(annotatedFieldElement, "Column name already used in this class");
-            }
-        }
-    }
-
-    //region Processing of annotated classes
-
-    /**
-     * Checks that element annotated with {@link StorIOSQLiteColumn} satisfies all required conditions
-     *
-     * @param annotatedField element annotated with {@link StorIOSQLiteColumn}
-     */
-    private static void validateAnnotatedField(@NotNull final Element annotatedField) {
-        // we expect here that annotatedElement is Field, annotation requires that via @Target
-
-        final Element enclosingElement = annotatedField.getEnclosingElement();
-
-        if (!enclosingElement.getKind().equals(CLASS)) {
-            throw new ProcessingException(
-                    annotatedField,
-                    "Please apply " + StorIOSQLiteType.class.getSimpleName() + " to fields of class: " + annotatedField.getSimpleName()
-            );
-        }
-
-        if (enclosingElement.getAnnotation(StorIOSQLiteType.class) == null) {
-            throw new ProcessingException(
-                    annotatedField,
-                    "Please annotate class " + enclosingElement.getSimpleName() + " with " + StorIOSQLiteType.class.getSimpleName()
-            );
-        }
-
-        if (annotatedField.getModifiers().contains(PRIVATE)) {
-            throw new ProcessingException(
-                    annotatedField,
-                    StorIOSQLiteColumn.class.getSimpleName() + " can not be applied to private field: " + annotatedField.getSimpleName()
-            );
-        }
-
-        if (annotatedField.getModifiers().contains(FINAL)) {
-            throw new ProcessingException(
-                    annotatedField,
-                    StorIOSQLiteColumn.class.getSimpleName() + " can not be applied to final field: " + annotatedField.getSimpleName()
-            );
-        }
-    }
-
-    /**
-     * Processes annotated field and returns result of processing or throws exception
-     *
-     * @param annotatedField field that was annotated with {@link StorIOSQLiteColumn}
-     * @return non-null {@link StorIOSQLiteColumnMeta} with meta information about field
-     */
-    @NotNull
-    private static StorIOSQLiteColumnMeta processAnnotatedField(@NotNull final Element annotatedField) {
-        final JavaType javaType;
-
-        try {
-            javaType = JavaType.from(annotatedField.asType());
-        } catch (Exception e) {
-            throw new ProcessingException(annotatedField, "Unsupported type of field for "
-                    + StorIOSQLiteColumn.class.getSimpleName()
-                    + " annotation, if you need to serialize/deserialize field of that type "
-                    + "-> please write your own resolver: "
-                    + e.getMessage()
-            );
-        }
-
-        final StorIOSQLiteColumn storIOSQLiteColumn = annotatedField.getAnnotation(StorIOSQLiteColumn.class);
-
-        final String columnName = storIOSQLiteColumn.name();
-
-        if (columnName == null || columnName.length() == 0) {
-            throw new ProcessingException(annotatedField, "Column name is null or empty");
-        }
-
-        return new StorIOSQLiteColumnMeta(
-                annotatedField.getEnclosingElement(),
-                annotatedField,
-                annotatedField.getSimpleName().toString(),
-                javaType,
-                storIOSQLiteColumn
-        );
-    }
-
-    private static void validateAnnotatedClassesAndColumns(@NotNull Map<TypeElement, StorIOSQLiteTypeMeta> annotatedClasses) {
-        // check that each annotated class has columns with at least one key column
-        for (Map.Entry<TypeElement, StorIOSQLiteTypeMeta> annotatedClass : annotatedClasses.entrySet()) {
-            if (annotatedClass.getValue().columns.size() == 0) {
-                throw new ProcessingException(annotatedClass.getKey(),
-                        "Class marked with "
-                                + StorIOSQLiteType.class.getSimpleName()
-                                + " annotation should have at least one field marked with "
-                                + StorIOSQLiteColumn.class.getSimpleName()
-                                + " annotation");
-            }
-
-            boolean hasAtLeastOneKeyColumn = false;
-
-            for (StorIOSQLiteColumnMeta columnMeta : annotatedClass.getValue().columns.values()) {
-                if (columnMeta.storIOSQLiteColumn.key()) {
-                    hasAtLeastOneKeyColumn = true;
-                    break;
-                }
-            }
-
-            if (!hasAtLeastOneKeyColumn) {
-                throw new ProcessingException(annotatedClass.getKey(),
-                        "Class marked with "
-                                + StorIOSQLiteType.class.getSimpleName()
-                                + " annotation should have at least one KEY field marked with "
-                                + StorIOSQLiteColumn.class.getSimpleName() + " annotation");
-            }
-        }
-    }
-
-    //endregion
-
-    //region Processing of annotated fields
-
-    @Override
-    public synchronized void init(ProcessingEnvironment processingEnv) {
-        super.init(processingEnv);
-        filer = processingEnv.getFiler();
-        elementUtils = processingEnv.getElementUtils(); // why class name is "Elements" but method "getElementUtils()", OKAY..
-        messager = processingEnv.getMessager();
-    }
-
-    @Override
-    public Set<String> getSupportedAnnotationTypes() {
-        final Set<String> supportedAnnotations = new HashSet<String>(2);
-
-        supportedAnnotations.add(StorIOSQLiteType.class.getCanonicalName());
-        supportedAnnotations.add(StorIOSQLiteColumn.class.getCanonicalName());
-
-        return supportedAnnotations;
-    }
-
-    @Override
-    public SourceVersion getSupportedSourceVersion() {
-        return SourceVersion.latestSupported();
-    }
-
-    //endregion
-
-    /**
-     * For those who don't familiar with Annotation Processing API — this is the main method of Annotation Processor lifecycle
-     * <p>
-     * It will be after Java Compiler will find lang elements annotated with annotations from {@link #getSupportedAnnotationTypes()}
-     *
-     * @param annotations set of annotations
-     * @param roundEnv    environment of current processing round
-     * @return true if annotation processor should not be invoked in next rounds of annotation processing, false otherwise
-     */
-    @Override
-    public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
-        try {
-            final Map<TypeElement, StorIOSQLiteTypeMeta> annotatedClasses
-                    = processAnnotatedClasses(roundEnv, elementUtils);
-
-            processAnnotatedFields(roundEnv, annotatedClasses);
-
-            validateAnnotatedClassesAndColumns(annotatedClasses);
-
-            final PutResolverGenerator putResolverGenerator = new PutResolverGenerator();
-            final GetResolverGenerator getResolverGenerator = new GetResolverGenerator();
-            final DeleteResolverGenerator deleteResolverGenerator = new DeleteResolverGenerator();
-
-            for (StorIOSQLiteTypeMeta storIOSQLiteTypeMeta : annotatedClasses.values()) {
-                putResolverGenerator.generateJavaFile(storIOSQLiteTypeMeta).writeTo(filer);
-                getResolverGenerator.generateJavaFile(storIOSQLiteTypeMeta).writeTo(filer);
-                deleteResolverGenerator.generateJavaFile(storIOSQLiteTypeMeta).writeTo(filer);
-            }
-        } catch (ProcessingException e) {
-            messager.printMessage(ERROR, e.getMessage(), e.element());
-        } catch (Exception e) {
-            messager.printMessage(ERROR, "Problem occurred with StorIOSQLiteProcessor: " + e.getMessage());
-        }
-
-        return true;
-    }
-}
diff --git a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/Common.java b/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/Common.java
deleted file mode 100644
index df9e930..0000000
--- a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/Common.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor.generate;
-
-import com.squareup.javapoet.ClassName;
-
-class Common {
-
-    static final ClassName ANDROID_NON_NULL_ANNOTATION_CLASS_NAME = ClassName.get("android.support.annotation", "NonNull");
-
-    static final String INDENT = "    "; // 4 spaces
-}
diff --git a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/DeleteResolverGenerator.java b/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/DeleteResolverGenerator.java
deleted file mode 100644
index cf6d339..0000000
--- a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/DeleteResolverGenerator.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor.generate;
-
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteTypeMeta;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeSpec;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Map;
-
-import static com.pushtorefresh.storio.sqlite.processor.generate.Common.ANDROID_NON_NULL_ANNOTATION_CLASS_NAME;
-import static com.pushtorefresh.storio.sqlite.processor.generate.Common.INDENT;
-import static javax.lang.model.element.Modifier.PROTECTED;
-import static javax.lang.model.element.Modifier.PUBLIC;
-
-public class DeleteResolverGenerator {
-
-    @NotNull
-    public JavaFile generateJavaFile(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta) {
-        final ClassName storIOSQLiteTypeClassName = ClassName.get(storIOSQLiteTypeMeta.packageName, storIOSQLiteTypeMeta.simpleName);
-
-        final TypeSpec deleteResolver = TypeSpec.classBuilder(storIOSQLiteTypeMeta.simpleName + "StorIOSQLiteDeleteResolver")
-                .addJavadoc("Generated resolver for Delete Operation\n")
-                .addModifiers(PUBLIC)
-                .superclass(ParameterizedTypeName.get(ClassName.get("com.pushtorefresh.storio.sqlite.operation.delete", "DefaultDeleteResolver"), storIOSQLiteTypeClassName))
-                .addMethod(createMapToDeleteQueryMethodSpec(storIOSQLiteTypeMeta, storIOSQLiteTypeClassName))
-                .build();
-
-        return JavaFile
-                .builder(storIOSQLiteTypeMeta.packageName, deleteResolver)
-                .indent(INDENT)
-                .build();
-    }
-
-    @NotNull
-    MethodSpec createMapToDeleteQueryMethodSpec(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta, @NotNull ClassName storIOSQLiteTypeClassName) {
-        final Map<String, String> where = QueryGenerator.createWhere(storIOSQLiteTypeMeta, "object");
-
-        return MethodSpec.methodBuilder("mapToDeleteQuery")
-                .addJavadoc("{@inheritDoc}\n")
-                .addAnnotation(Override.class)
-                .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
-                .addModifiers(PROTECTED)
-                .returns(ClassName.get("com.pushtorefresh.storio.sqlite.query", "DeleteQuery"))
-                .addParameter(ParameterSpec.builder(storIOSQLiteTypeClassName, "object")
-                        .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
-                        .build())
-                .addCode("return DeleteQuery.builder()\n" +
-                                INDENT + ".table($S)\n" +
-                                INDENT + ".where($S)\n" +
-                                INDENT + ".whereArgs($L)\n" +
-                                INDENT + ".build();\n",
-                        storIOSQLiteTypeMeta.storIOSQLiteType.table(),
-                        where.get(QueryGenerator.WHERE_CLAUSE),
-                        where.get(QueryGenerator.WHERE_ARGS))
-                .build();
-    }
-}
diff --git a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/GetResolverGenerator.java b/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/GetResolverGenerator.java
deleted file mode 100644
index 445d4a9..0000000
--- a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/GetResolverGenerator.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor.generate;
-
-import com.pushtorefresh.storio.sqlite.processor.ProcessingException;
-import com.pushtorefresh.storio.sqlite.processor.introspection.JavaType;
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteColumnMeta;
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteTypeMeta;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeSpec;
-
-import org.jetbrains.annotations.NotNull;
-
-import static com.pushtorefresh.storio.sqlite.processor.generate.Common.ANDROID_NON_NULL_ANNOTATION_CLASS_NAME;
-import static com.pushtorefresh.storio.sqlite.processor.generate.Common.INDENT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.BOOLEAN;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.BOOLEAN_OBJECT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.DOUBLE;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.DOUBLE_OBJECT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.FLOAT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.FLOAT_OBJECT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.INTEGER;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.INTEGER_OBJECT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.LONG;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.LONG_OBJECT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.SHORT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.SHORT_OBJECT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.STRING;
-import static javax.lang.model.element.Modifier.PUBLIC;
-
-public class GetResolverGenerator {
-
-    @NotNull
-    public JavaFile generateJavaFile(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta) {
-        final ClassName storIOSQLiteTypeClassName = ClassName.get(storIOSQLiteTypeMeta.packageName, storIOSQLiteTypeMeta.simpleName);
-
-        final TypeSpec getResolver = TypeSpec.classBuilder(storIOSQLiteTypeMeta.simpleName + "StorIOSQLiteGetResolver")
-                .addJavadoc("Generated resolver for Get Operation\n")
-                .addModifiers(PUBLIC)
-                .superclass(ParameterizedTypeName.get(ClassName.get("com.pushtorefresh.storio.sqlite.operation.get", "DefaultGetResolver"), storIOSQLiteTypeClassName))
-                .addMethod(createMapFromCursorMethodSpec(storIOSQLiteTypeMeta, storIOSQLiteTypeClassName))
-                .build();
-
-        return JavaFile
-                .builder(storIOSQLiteTypeMeta.packageName, getResolver)
-                .indent(INDENT)
-                .build();
-    }
-
-    @NotNull
-    MethodSpec createMapFromCursorMethodSpec(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta, @NotNull ClassName storIOSQLiteTypeClassName) {
-        final MethodSpec.Builder builder = MethodSpec.methodBuilder("mapFromCursor")
-                .addJavadoc("{@inheritDoc}\n")
-                .addAnnotation(Override.class)
-                .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
-                .addModifiers(PUBLIC)
-                .returns(storIOSQLiteTypeClassName)
-                .addParameter(ParameterSpec.builder(ClassName.get("android.database", "Cursor"), "cursor")
-                        .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
-                        .build())
-                .addStatement("$T object = new $T()", storIOSQLiteTypeClassName, storIOSQLiteTypeClassName)
-                .addCode("\n");
-
-        for (final StorIOSQLiteColumnMeta columnMeta : storIOSQLiteTypeMeta.columns.values()) {
-            final String columnIndex = "cursor.getColumnIndex(\"" + columnMeta.storIOSQLiteColumn.name() + "\")";
-
-            final String getFromCursor;
-
-            final JavaType javaType = columnMeta.javaType;
-
-            if (javaType == BOOLEAN || javaType == BOOLEAN_OBJECT) {
-                getFromCursor = "getInt(" + columnIndex + ") == 1";
-            } else if (javaType == SHORT || javaType == SHORT_OBJECT) {
-                getFromCursor = "getShort(" + columnIndex + ")";
-            } else if (javaType == INTEGER || javaType == INTEGER_OBJECT) {
-                getFromCursor = "getInt(" + columnIndex + ")";
-            } else if (javaType == LONG || javaType == LONG_OBJECT) {
-                getFromCursor = "getLong(" + columnIndex + ")";
-            } else if (javaType == FLOAT || javaType == FLOAT_OBJECT) {
-                getFromCursor = "getFloat(" + columnIndex + ")";
-            } else if (javaType == DOUBLE || javaType == DOUBLE_OBJECT) {
-                getFromCursor = "getDouble(" + columnIndex + ")";
-            } else if (javaType == STRING) {
-                getFromCursor = "getString(" + columnIndex + ")";
-            } else {
-                throw new ProcessingException(columnMeta.element, "Can not generate GetResolver for field");
-            }
-
-            builder
-                    .addStatement("object.$L = cursor.$L", columnMeta.fieldName, getFromCursor);
-        }
-
-        return builder
-                .addCode("\n")
-                .addStatement("return object")
-                .build();
-    }
-}
diff --git a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/PutResolverGenerator.java b/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/PutResolverGenerator.java
deleted file mode 100644
index b4b37a4..0000000
--- a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/PutResolverGenerator.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor.generate;
-
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteColumnMeta;
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteTypeMeta;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeSpec;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Map;
-
-import static com.pushtorefresh.storio.sqlite.processor.generate.Common.ANDROID_NON_NULL_ANNOTATION_CLASS_NAME;
-import static com.pushtorefresh.storio.sqlite.processor.generate.Common.INDENT;
-import static javax.lang.model.element.Modifier.PROTECTED;
-import static javax.lang.model.element.Modifier.PUBLIC;
-
-public class PutResolverGenerator {
-
-    @NotNull
-    public JavaFile generateJavaFile(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta) {
-        final ClassName storIOSQLiteTypeClassName = ClassName.get(storIOSQLiteTypeMeta.packageName, storIOSQLiteTypeMeta.simpleName);
-
-        final TypeSpec putResolver = TypeSpec.classBuilder(storIOSQLiteTypeMeta.simpleName + "StorIOSQLitePutResolver")
-                .addJavadoc("Generated resolver for Put Operation\n")
-                .addModifiers(PUBLIC)
-                .superclass(ParameterizedTypeName.get(ClassName.get("com.pushtorefresh.storio.sqlite.operation.put", "DefaultPutResolver"), storIOSQLiteTypeClassName))
-                .addMethod(createMapToInsertQueryMethodSpec(storIOSQLiteTypeMeta, storIOSQLiteTypeClassName))
-                .addMethod(createMapToUpdateQueryMethodSpec(storIOSQLiteTypeMeta, storIOSQLiteTypeClassName))
-                .addMethod(createMapToContentValuesMethodSpec(storIOSQLiteTypeMeta, storIOSQLiteTypeClassName))
-                .build();
-
-        return JavaFile
-                .builder(storIOSQLiteTypeMeta.packageName, putResolver)
-                .indent(INDENT)
-                .build();
-    }
-
-    @NotNull
-    MethodSpec createMapToInsertQueryMethodSpec(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta, @NotNull ClassName storIOSQLiteTypeClassName) {
-        return MethodSpec.methodBuilder("mapToInsertQuery")
-                .addJavadoc("{@inheritDoc}\n")
-                .addAnnotation(Override.class)
-                .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
-                .addModifiers(PROTECTED)
-                .returns(ClassName.get("com.pushtorefresh.storio.sqlite.query", "InsertQuery"))
-                .addParameter(ParameterSpec.builder(storIOSQLiteTypeClassName, "object")
-                        .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
-                        .build())
-                .addCode("return InsertQuery.builder()\n" +
-                                INDENT + ".table($S)\n" +
-                                INDENT + ".build();\n",
-                        storIOSQLiteTypeMeta.storIOSQLiteType.table())
-                .build();
-    }
-
-    @NotNull
-    MethodSpec createMapToUpdateQueryMethodSpec(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta, @NotNull ClassName storIOSQLiteTypeClassName) {
-        final Map<String, String> where = QueryGenerator.createWhere(storIOSQLiteTypeMeta, "object");
-
-        return MethodSpec.methodBuilder("mapToUpdateQuery")
-                .addJavadoc("{@inheritDoc}\n")
-                .addAnnotation(Override.class)
-                .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
-                .addModifiers(PROTECTED)
-                .returns(ClassName.get("com.pushtorefresh.storio.sqlite.query", "UpdateQuery"))
-                .addParameter(ParameterSpec.builder(storIOSQLiteTypeClassName, "object")
-                        .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
-                        .build())
-                .addCode("return UpdateQuery.builder()\n" +
-                                INDENT + ".table($S)\n" +
-                                INDENT + ".where($S)\n" +
-                                INDENT + ".whereArgs($L)\n" +
-                                INDENT + ".build();\n",
-                        storIOSQLiteTypeMeta.storIOSQLiteType.table(),
-                        where.get(QueryGenerator.WHERE_CLAUSE),
-                        where.get(QueryGenerator.WHERE_ARGS))
-                .build();
-    }
-
-    @NotNull
-    MethodSpec createMapToContentValuesMethodSpec(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta, @NotNull ClassName storIOSQLiteTypeClassName) {
-        final MethodSpec.Builder builder = MethodSpec.methodBuilder("mapToContentValues")
-                .addJavadoc("{@inheritDoc}\n")
-                .addAnnotation(Override.class)
-                .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
-                .addModifiers(PUBLIC)
-                .returns(ClassName.get("android.content", "ContentValues"))
-                .addParameter(ParameterSpec.builder(storIOSQLiteTypeClassName, "object")
-                        .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
-                        .build())
-                .addStatement("ContentValues contentValues = new ContentValues($L)", storIOSQLiteTypeMeta.columns.size())
-                .addCode("\n");
-
-        for (StorIOSQLiteColumnMeta columnMeta : storIOSQLiteTypeMeta.columns.values()) {
-            builder.addStatement(
-                    "contentValues.put($S, $L)",
-                    columnMeta.storIOSQLiteColumn.name(),
-                    "object." + columnMeta.fieldName
-            );
-        }
-
-        return builder
-                .addCode("\n")
-                .addStatement("return contentValues")
-                .build();
-    }
-}
diff --git a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/QueryGenerator.java b/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/QueryGenerator.java
deleted file mode 100644
index 3ffdf85..0000000
--- a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/generate/QueryGenerator.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor.generate;
-
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteColumnMeta;
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteTypeMeta;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-public class QueryGenerator {
-
-    public static final String WHERE_CLAUSE = "where";
-    public static final String WHERE_ARGS = "whereArgs";
-
-    @NotNull
-    public static Map<String, String> createWhere(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta, @NotNull String varName) {
-        final StringBuilder whereClause = new StringBuilder();
-        final StringBuilder whereArgs = new StringBuilder();
-
-        int i = 0;
-
-        for (final StorIOSQLiteColumnMeta columnMeta : storIOSQLiteTypeMeta.columns.values()) {
-            if (columnMeta.storIOSQLiteColumn.key()) {
-                if (i == 0) {
-                    whereClause
-                            .append(columnMeta.storIOSQLiteColumn.name())
-                            .append(" = ?");
-
-                    whereArgs
-                            .append(varName)
-                            .append(".")
-                            .append(columnMeta.fieldName);
-                } else {
-                    whereClause
-                            .append(" AND ")
-                            .append(columnMeta.storIOSQLiteColumn.name())
-                            .append(" = ?");
-
-                    whereArgs
-                            .append(", ")
-                            .append(varName)
-                            .append(".")
-                            .append(columnMeta.fieldName);
-                }
-
-                i++;
-            }
-        }
-
-        if (whereClause.length() == 0 || whereArgs.length() == 0) {
-            return Collections.emptyMap();
-        } else {
-            final Map<String, String> result = new HashMap<String, String>(2);
-
-            result.put(WHERE_CLAUSE, whereClause.toString()); // example: "email = ? AND user_id = ?"
-            result.put(WHERE_ARGS, whereArgs.toString()); // example: "object.email, object.userId"
-
-            return result;
-        }
-    }
-}
diff --git a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/introspection/JavaType.java b/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/introspection/JavaType.java
deleted file mode 100644
index 1739749..0000000
--- a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/introspection/JavaType.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor.introspection;
-
-import org.jetbrains.annotations.NotNull;
-
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-
-public enum JavaType {
-
-    BOOLEAN,
-    BOOLEAN_OBJECT,
-    SHORT,
-    SHORT_OBJECT,
-    INTEGER,
-    INTEGER_OBJECT,
-    LONG,
-    LONG_OBJECT,
-    FLOAT,
-    FLOAT_OBJECT,
-    DOUBLE,
-    DOUBLE_OBJECT,
-    STRING;
-
-    @NotNull
-    public static JavaType from(@NotNull TypeMirror typeMirror) {
-        final TypeKind typeKind = typeMirror.getKind();
-        final String typeName = typeMirror.toString(); // fqn of type, for example java.lang.String
-
-        if (typeKind == TypeKind.BOOLEAN) {
-            return BOOLEAN;
-        } else if ("java.lang.Boolean".equals(typeName)) {
-            return BOOLEAN_OBJECT;
-        } else if (typeKind == TypeKind.SHORT) {
-            return SHORT;
-        } else if ("java.lang.Short".equals(typeName)) {
-            return SHORT_OBJECT;
-        } else if (typeKind == TypeKind.INT) {
-            return INTEGER;
-        } else if ("java.lang.Integer".equals(typeName)) {
-            return INTEGER_OBJECT;
-        } else if (typeKind == TypeKind.LONG) {
-            return LONG;
-        } else if ("java.lang.Long".equals(typeName)) {
-            return LONG_OBJECT;
-        } else if (typeKind == TypeKind.FLOAT) {
-            return FLOAT;
-        } else if ("java.lang.Float".equals(typeName)) {
-            return FLOAT_OBJECT;
-        } else if (typeKind == TypeKind.DOUBLE) {
-            return DOUBLE;
-        } else if ("java.lang.Double".equals(typeName)) {
-            return DOUBLE_OBJECT;
-        } else if ("java.lang.String".equals(typeName)) {
-            return STRING;
-        } else {
-            throw new IllegalArgumentException("Unsupported type: " + typeMirror);
-        }
-    }
-}
diff --git a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/introspection/StorIOSQLiteColumnMeta.java b/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/introspection/StorIOSQLiteColumnMeta.java
deleted file mode 100644
index 4fa8078..0000000
--- a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/introspection/StorIOSQLiteColumnMeta.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor.introspection;
-
-import com.pushtorefresh.storio.sqlite.annotation.StorIOSQLiteColumn;
-
-import org.jetbrains.annotations.NotNull;
-
-import javax.lang.model.element.Element;
-
-public class StorIOSQLiteColumnMeta {
-
-    @NotNull
-    public final Element enclosingElement;
-
-    @NotNull
-    public final Element element;
-
-    @NotNull
-    public final String fieldName;
-
-    @NotNull
-    public final JavaType javaType;
-
-    @NotNull
-    public final StorIOSQLiteColumn storIOSQLiteColumn;
-
-    public StorIOSQLiteColumnMeta(@NotNull Element enclosingElement, @NotNull Element element, @NotNull String fieldName, @NotNull JavaType javaType, @NotNull StorIOSQLiteColumn storIOSQLiteColumn) {
-        this.enclosingElement = enclosingElement;
-        this.element = element;
-        this.fieldName = fieldName;
-        this.javaType = javaType;
-        this.storIOSQLiteColumn = storIOSQLiteColumn;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        StorIOSQLiteColumnMeta that = (StorIOSQLiteColumnMeta) o;
-
-        if (!enclosingElement.equals(that.enclosingElement)) return false;
-        if (!element.equals(that.element)) return false;
-        if (!fieldName.equals(that.fieldName)) return false;
-        if (javaType != that.javaType) return false;
-        return storIOSQLiteColumn.equals(that.storIOSQLiteColumn);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = enclosingElement.hashCode();
-        result = 31 * result + element.hashCode();
-        result = 31 * result + fieldName.hashCode();
-        result = 31 * result + javaType.hashCode();
-        result = 31 * result + storIOSQLiteColumn.hashCode();
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "StorIOSQLiteColumnMeta{" +
-                "enclosingElement=" + enclosingElement +
-                ", element=" + element +
-                ", fieldName='" + fieldName + '\'' +
-                ", javaType=" + javaType +
-                ", storIOSQLiteColumn=" + storIOSQLiteColumn +
-                '}';
-    }
-}
diff --git a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/introspection/StorIOSQLiteTypeMeta.java b/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/introspection/StorIOSQLiteTypeMeta.java
deleted file mode 100644
index ecb015b..0000000
--- a/storio-sqlite-annotation-processor/src/main/java/com/pushtorefresh/storio/sqlite/processor/introspection/StorIOSQLiteTypeMeta.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor.introspection;
-
-import com.pushtorefresh.storio.sqlite.annotation.StorIOSQLiteType;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class StorIOSQLiteTypeMeta {
-
-    @NotNull
-    public final String simpleName;
-
-    @NotNull
-    public final String packageName;
-
-    @NotNull
-    public final StorIOSQLiteType storIOSQLiteType;
-
-    /**
-     * Yep, this is MODIFIABLE Map, please use it carefully
-     */
-    @NotNull
-    public final Map<String, StorIOSQLiteColumnMeta> columns = new HashMap<String, StorIOSQLiteColumnMeta>();
-
-    public StorIOSQLiteTypeMeta(@NotNull String simpleName, @NotNull String packageName, @NotNull StorIOSQLiteType storIOSQLiteType) {
-        this.simpleName = simpleName;
-        this.packageName = packageName;
-        this.storIOSQLiteType = storIOSQLiteType;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        StorIOSQLiteTypeMeta that = (StorIOSQLiteTypeMeta) o;
-
-        if (!simpleName.equals(that.simpleName)) return false;
-        if (!packageName.equals(that.packageName)) return false;
-        if (!storIOSQLiteType.equals(that.storIOSQLiteType)) return false;
-        return columns.equals(that.columns);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = simpleName.hashCode();
-        result = 31 * result + packageName.hashCode();
-        result = 31 * result + storIOSQLiteType.hashCode();
-        result = 31 * result + columns.hashCode();
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "StorIOSQLiteTypeMeta{" +
-                "simpleName='" + simpleName + '\'' +
-                ", packageName='" + packageName + '\'' +
-                ", storIOSQLiteType=" + storIOSQLiteType +
-                ", columns=" + columns +
-                '}';
-    }
-}
diff --git a/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/DeleteResolverGeneratorTest.java b/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/DeleteResolverGeneratorTest.java
deleted file mode 100644
index 117beea..0000000
--- a/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/DeleteResolverGeneratorTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor.generate;
-
-import com.pushtorefresh.storio.sqlite.annotation.StorIOSQLiteColumn;
-import com.pushtorefresh.storio.sqlite.annotation.StorIOSQLiteType;
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteColumnMeta;
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteTypeMeta;
-import com.squareup.javapoet.JavaFile;
-
-import org.junit.Test;
-
-import java.io.IOException;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class DeleteResolverGeneratorTest {
-
-    @Test
-    public void generateJavaFile() throws IOException {
-        final StorIOSQLiteType storIOSQLiteType = mock(StorIOSQLiteType.class);
-
-        when(storIOSQLiteType.table()).thenReturn("test_table");
-
-        final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = new StorIOSQLiteTypeMeta(
-                "TestItem",
-                "com.test",
-                storIOSQLiteType
-        );
-
-        final StorIOSQLiteColumn storIOSQLiteColumn1 = mock(StorIOSQLiteColumn.class);
-        when(storIOSQLiteColumn1.name()).thenReturn("column1");
-        final StorIOSQLiteColumnMeta storIOSQLiteColumnMeta1 = new StorIOSQLiteColumnMeta(
-                null,
-                null,
-                "field1",
-                null,
-                storIOSQLiteColumn1
-        );
-        storIOSQLiteTypeMeta.columns.put("column1", storIOSQLiteColumnMeta1);
-
-        final StorIOSQLiteColumn storIOSQLiteColumn2 = mock(StorIOSQLiteColumn.class);
-        when(storIOSQLiteColumn2.name()).thenReturn("column2");
-        final StorIOSQLiteColumnMeta storIOSQLiteColumnMeta2 = new StorIOSQLiteColumnMeta(
-                null,
-                null,
-                "field2",
-                null,
-                storIOSQLiteColumn2
-        );
-        storIOSQLiteTypeMeta.columns.put("column2", storIOSQLiteColumnMeta2);
-
-        final JavaFile javaFile = new DeleteResolverGenerator().generateJavaFile(storIOSQLiteTypeMeta);
-        final StringBuilder out = new StringBuilder();
-        javaFile.writeTo(out);
-
-        assertEquals("package com.test;\n" +
-                "\n" +
-                "import android.support.annotation.NonNull;\n" +
-                "import com.pushtorefresh.storio.sqlite.operation.delete.DefaultDeleteResolver;\n" +
-                "import com.pushtorefresh.storio.sqlite.query.DeleteQuery;\n" +
-                "import java.lang.Override;\n" +
-                "\n" +
-                "/**\n" +
-                " * Generated resolver for Delete Operation\n" +
-                " */\n" +
-                "public class TestItemStorIOSQLiteDeleteResolver extends DefaultDeleteResolver<TestItem> {\n" +
-                "    /**\n" +
-                "     * {@inheritDoc}\n" +
-                "     */\n" +
-                "    @Override\n" +
-                "    @NonNull\n" +
-                "    protected DeleteQuery mapToDeleteQuery(@NonNull TestItem object) {\n" +
-                "        return DeleteQuery.builder()\n" +
-                "            .table(\"test_table\")\n" +
-                "            .where(null)\n" +
-                "            .whereArgs(null)\n" +
-                "            .build();\n" +
-                "    }\n" +
-                "}\n", out.toString());
-    }
-}
diff --git a/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/GetResolverGeneratorTest.java b/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/GetResolverGeneratorTest.java
deleted file mode 100644
index 5e716d6..0000000
--- a/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/GetResolverGeneratorTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor.generate;
-
-import com.pushtorefresh.storio.sqlite.annotation.StorIOSQLiteColumn;
-import com.pushtorefresh.storio.sqlite.annotation.StorIOSQLiteType;
-import com.pushtorefresh.storio.sqlite.processor.introspection.JavaType;
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteColumnMeta;
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteTypeMeta;
-import com.squareup.javapoet.JavaFile;
-
-import org.junit.Test;
-
-import java.io.IOException;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class GetResolverGeneratorTest {
-
-    @Test
-    public void generateJavaFileTest() throws IOException {
-        final StorIOSQLiteType storIOSQLiteType = mock(StorIOSQLiteType.class);
-
-        when(storIOSQLiteType.table()).thenReturn("test_table");
-
-        final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = new StorIOSQLiteTypeMeta(
-                "TestItem",
-                "com.test",
-                storIOSQLiteType
-        );
-
-        final StorIOSQLiteColumn storIOSQLiteColumn1 = mock(StorIOSQLiteColumn.class);
-        when(storIOSQLiteColumn1.name()).thenReturn("column1");
-        final StorIOSQLiteColumnMeta storIOSQLiteColumnMeta1 = new StorIOSQLiteColumnMeta(
-                null,
-                null,
-                "field1",
-                JavaType.BOOLEAN,
-                storIOSQLiteColumn1
-        );
-        storIOSQLiteTypeMeta.columns.put("column1", storIOSQLiteColumnMeta1);
-
-        final StorIOSQLiteColumn storIOSQLiteColumn2 = mock(StorIOSQLiteColumn.class);
-        when(storIOSQLiteColumn2.name()).thenReturn("column2");
-        final StorIOSQLiteColumnMeta storIOSQLiteColumnMeta2 = new StorIOSQLiteColumnMeta(
-                null,
-                null,
-                "field2",
-                JavaType.STRING,
-                storIOSQLiteColumn2
-        );
-        storIOSQLiteTypeMeta.columns.put("column2", storIOSQLiteColumnMeta2);
-
-        final JavaFile javaFile = new GetResolverGenerator().generateJavaFile(storIOSQLiteTypeMeta);
-        final StringBuilder out = new StringBuilder();
-        javaFile.writeTo(out);
-
-        assertEquals("package com.test;\n" +
-                "\n" +
-                "import android.database.Cursor;\n" +
-                "import android.support.annotation.NonNull;\n" +
-                "import com.pushtorefresh.storio.sqlite.operation.get.DefaultGetResolver;\n" +
-                "import java.lang.Override;\n" +
-                "\n" +
-                "/**\n" +
-                " * Generated resolver for Get Operation\n" +
-                " */\n" +
-                "public class TestItemStorIOSQLiteGetResolver extends DefaultGetResolver<TestItem> {\n" +
-                "    /**\n" +
-                "     * {@inheritDoc}\n" +
-                "     */\n" +
-                "    @Override\n" +
-                "    @NonNull\n" +
-                "    public TestItem mapFromCursor(@NonNull Cursor cursor) {\n" +
-                "        TestItem object = new TestItem();\n" +
-                "\n" +
-                "        object.field1 = cursor.getInt(cursor.getColumnIndex(\"column1\")) == 1;\n" +
-                "        object.field2 = cursor.getString(cursor.getColumnIndex(\"column2\"));\n" +
-                "\n" +
-                "        return object;\n" +
-                "    }\n" +
-                "}\n", out.toString());
-    }
-}
diff --git a/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/PutResolverGeneratorTest.java b/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/PutResolverGeneratorTest.java
deleted file mode 100644
index 2acb9fa..0000000
--- a/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/PutResolverGeneratorTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor.generate;
-
-import com.pushtorefresh.storio.sqlite.annotation.StorIOSQLiteColumn;
-import com.pushtorefresh.storio.sqlite.annotation.StorIOSQLiteType;
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteColumnMeta;
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteTypeMeta;
-import com.squareup.javapoet.JavaFile;
-
-import org.junit.Test;
-
-import java.io.IOException;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class PutResolverGeneratorTest {
-
-    @Test
-    public void generateJavaFile() throws IOException {
-        final PutResolverGenerator putResolverGenerator = new PutResolverGenerator();
-
-        final StorIOSQLiteType storIOSQLiteType = mock(StorIOSQLiteType.class);
-
-        when(storIOSQLiteType.table()).thenReturn("test_table");
-
-        final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = new StorIOSQLiteTypeMeta("TestItem", "com.test", storIOSQLiteType);
-
-        final StorIOSQLiteColumn storIOSQLiteColumn1 = mock(StorIOSQLiteColumn.class);
-        when(storIOSQLiteColumn1.name()).thenReturn("column1");
-        when(storIOSQLiteColumn1.key()).thenReturn(true);
-        final StorIOSQLiteColumnMeta storIOSQLiteColumnMeta1 = new StorIOSQLiteColumnMeta(
-                null,
-                null,
-                "column1Field",
-                null,
-                storIOSQLiteColumn1
-        );
-        storIOSQLiteTypeMeta.columns.put("column1", storIOSQLiteColumnMeta1);
-
-        final StorIOSQLiteColumn storIOSQLiteColumn2 = mock(StorIOSQLiteColumn.class);
-        when(storIOSQLiteColumn2.name()).thenReturn("column2");
-        when(storIOSQLiteColumn2.key()).thenReturn(false);
-        final StorIOSQLiteColumnMeta storIOSQLiteColumnMeta2 = new StorIOSQLiteColumnMeta(
-                null,
-                null,
-                "column2Field",
-                null,
-                storIOSQLiteColumn2
-        );
-        storIOSQLiteTypeMeta.columns.put("column2", storIOSQLiteColumnMeta2);
-
-        final JavaFile javaFile = putResolverGenerator.generateJavaFile(storIOSQLiteTypeMeta);
-        final StringBuilder out = new StringBuilder();
-        javaFile.writeTo(out);
-
-        assertEquals("package com.test;\n" +
-                "\n" +
-                "import android.content.ContentValues;\n" +
-                "import android.support.annotation.NonNull;\n" +
-                "import com.pushtorefresh.storio.sqlite.operation.put.DefaultPutResolver;\n" +
-                "import com.pushtorefresh.storio.sqlite.query.InsertQuery;\n" +
-                "import com.pushtorefresh.storio.sqlite.query.UpdateQuery;\n" +
-                "import java.lang.Override;\n" +
-                "\n" +
-                "/**\n" +
-                " * Generated resolver for Put Operation\n" +
-                " */\n" +
-                "public class TestItemStorIOSQLitePutResolver extends DefaultPutResolver<TestItem> {\n" +
-                "    /**\n" +
-                "     * {@inheritDoc}\n" +
-                "     */\n" +
-                "    @Override\n" +
-                "    @NonNull\n" +
-                "    protected InsertQuery mapToInsertQuery(@NonNull TestItem object) {\n" +
-                "        return InsertQuery.builder()\n" +
-                "            .table(\"test_table\")\n" +
-                "            .build();\n" +
-                "    }\n" +
-                "\n" +
-                "    /**\n" +
-                "     * {@inheritDoc}\n" +
-                "     */\n" +
-                "    @Override\n" +
-                "    @NonNull\n" +
-                "    protected UpdateQuery mapToUpdateQuery(@NonNull TestItem object) {\n" +
-                "        return UpdateQuery.builder()\n" +
-                "            .table(\"test_table\")\n" +
-                "            .where(\"column1 = ?\")\n" +
-                "            .whereArgs(object.column1Field)\n" +
-                "            .build();\n" +
-                "    }\n" +
-                "\n" +
-                "    /**\n" +
-                "     * {@inheritDoc}\n" +
-                "     */\n" +
-                "    @Override\n" +
-                "    @NonNull\n" +
-                "    public ContentValues mapToContentValues(@NonNull TestItem object) {\n" +
-                "        ContentValues contentValues = new ContentValues(2);\n" +
-                "\n" +
-                "        contentValues.put(\"column1\", object.column1Field);\n" +
-                "        contentValues.put(\"column2\", object.column2Field);\n" +
-                "\n" +
-                "        return contentValues;\n" +
-                "    }\n" +
-                "}\n", out.toString());
-    }
-}
diff --git a/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/QueryGeneratorTest.java b/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/QueryGeneratorTest.java
deleted file mode 100644
index 41584ae..0000000
--- a/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/generate/QueryGeneratorTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor.generate;
-
-import com.pushtorefresh.storio.sqlite.annotation.StorIOSQLiteColumn;
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteColumnMeta;
-import com.pushtorefresh.storio.sqlite.processor.introspection.StorIOSQLiteTypeMeta;
-
-import org.junit.Test;
-
-import java.util.Collections;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class QueryGeneratorTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void createWhereNullStorIOSQLiteTypeMeta() {
-        QueryGenerator.createWhere(null, "object");
-    }
-
-    @Test
-    public void createWhereNoColumns() {
-        final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = new StorIOSQLiteTypeMeta(null, null, null);
-        assertEquals(Collections.emptyMap(), QueryGenerator.createWhere(storIOSQLiteTypeMeta, "object"));
-    }
-
-    @Test
-    public void createWhereNoKeyColumns() {
-        final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = new StorIOSQLiteTypeMeta(null, null, null);
-
-        final StorIOSQLiteColumn storIOSQLiteColumn1 = mock(StorIOSQLiteColumn.class);
-        when(storIOSQLiteColumn1.key()).thenReturn(false);
-        storIOSQLiteTypeMeta.columns.put("column1", new StorIOSQLiteColumnMeta(null, null, null, null, storIOSQLiteColumn1));
-
-        final StorIOSQLiteColumn storIOSQLiteColumn2 = mock(StorIOSQLiteColumn.class);
-        when(storIOSQLiteColumn2.key()).thenReturn(false);
-        storIOSQLiteTypeMeta.columns.put("column2", new StorIOSQLiteColumnMeta(null, null, null, null, storIOSQLiteColumn2));
-
-        assertEquals(Collections.emptyMap(), QueryGenerator.createWhere(storIOSQLiteTypeMeta, "object"));
-    }
-
-    @Test
-    public void createWhereOneKeyColumn() {
-        final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = new StorIOSQLiteTypeMeta(null, null, null);
-
-        final StorIOSQLiteColumn storIOSQLiteColumn1 = mock(StorIOSQLiteColumn.class);
-        when(storIOSQLiteColumn1.key()).thenReturn(false);
-        storIOSQLiteTypeMeta.columns.put("column1", new StorIOSQLiteColumnMeta(null, null, null, null, storIOSQLiteColumn1));
-
-        final StorIOSQLiteColumn storIOSQLiteColumn2 = mock(StorIOSQLiteColumn.class);
-        when(storIOSQLiteColumn2.key()).thenReturn(true);
-        when(storIOSQLiteColumn2.name()).thenReturn("column2");
-        storIOSQLiteTypeMeta.columns.put("column2", new StorIOSQLiteColumnMeta(null, null, "testField1", null, storIOSQLiteColumn2));
-
-        final StorIOSQLiteColumn storIOSQLiteColumn3 = mock(StorIOSQLiteColumn.class);
-        when(storIOSQLiteColumn3.key()).thenReturn(false);
-        storIOSQLiteTypeMeta.columns.put("column3", new StorIOSQLiteColumnMeta(null, null, null, null, storIOSQLiteColumn3));
-
-        final Map<String, String> where = QueryGenerator.createWhere(storIOSQLiteTypeMeta, "object");
-
-        assertEquals("column2 = ?", where.get(QueryGenerator.WHERE_CLAUSE));
-        assertEquals("object.testField1", where.get(QueryGenerator.WHERE_ARGS));
-    }
-
-    @Test
-    public void createWhereMultipleKeyColumns() {
-        final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = new StorIOSQLiteTypeMeta(null, null, null);
-
-        final StorIOSQLiteColumn storIOSQLiteColumn1 = mock(StorIOSQLiteColumn.class);
-        when(storIOSQLiteColumn1.key()).thenReturn(true);
-        when(storIOSQLiteColumn1.name()).thenReturn("column1");
-        storIOSQLiteTypeMeta.columns.put("column1", new StorIOSQLiteColumnMeta(null, null, "testField1", null, storIOSQLiteColumn1));
-
-        final StorIOSQLiteColumn storIOSQLiteColumn2 = mock(StorIOSQLiteColumn.class);
-        when(storIOSQLiteColumn2.key()).thenReturn(false);
-        storIOSQLiteTypeMeta.columns.put("column2", new StorIOSQLiteColumnMeta(null, null, null, null, storIOSQLiteColumn2));
-
-        final StorIOSQLiteColumn storIOSQLiteColumn3 = mock(StorIOSQLiteColumn.class);
-        when(storIOSQLiteColumn3.key()).thenReturn(true);
-        when(storIOSQLiteColumn3.name()).thenReturn("column3");
-        storIOSQLiteTypeMeta.columns.put("column3", new StorIOSQLiteColumnMeta(null, null, "testField3", null, storIOSQLiteColumn3));
-
-        final Map<String, String> where = QueryGenerator.createWhere(storIOSQLiteTypeMeta, "object");
-
-        assertEquals("column1 = ? AND column3 = ?", where.get(QueryGenerator.WHERE_CLAUSE));
-        assertEquals("object.testField1, object.testField3", where.get(QueryGenerator.WHERE_ARGS));
-    }
-}
diff --git a/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/introspection/JavaTypeTest.java b/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/introspection/JavaTypeTest.java
deleted file mode 100644
index d2ba613..0000000
--- a/storio-sqlite-annotation-processor/src/test/java/com/pushtorefresh/storio/sqlite/processor/introspection/JavaTypeTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package com.pushtorefresh.storio.sqlite.processor.introspection;
-
-import org.junit.Test;
-
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.BOOLEAN;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.BOOLEAN_OBJECT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.DOUBLE;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.DOUBLE_OBJECT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.FLOAT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.FLOAT_OBJECT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.INTEGER;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.INTEGER_OBJECT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.LONG;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.LONG_OBJECT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.SHORT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.SHORT_OBJECT;
-import static com.pushtorefresh.storio.sqlite.processor.introspection.JavaType.STRING;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class JavaTypeTest {
-
-    private static TypeMirror mockTypeMirror(TypeKind typeKind, String typeName) {
-        final TypeMirror typeMirror = mock(TypeMirror.class);
-
-        when(typeMirror.getKind())
-                .thenReturn(typeKind);
-
-        when(typeMirror.toString())
-                .thenReturn(typeName);
-
-        return typeMirror;
-    }
-
-    @Test
-    public void fromBoolean() {
-        final TypeMirror typeMirror = mockTypeMirror(TypeKind.BOOLEAN, null);
-        assertEquals(BOOLEAN, JavaType.from(typeMirror));
-    }
-
-    @Test
-    public void fromBooleanObject() {
-        final TypeMirror typeMirror = mockTypeMirror(null, "java.lang.Boolean");
-        assertEquals(BOOLEAN_OBJECT, JavaType.from(typeMirror));
-    }
-
-    @Test
-    public void fromShort() {
-        final TypeMirror typeMirror = mockTypeMirror(TypeKind.SHORT, null);
-        assertEquals(SHORT, JavaType.from(typeMirror));
-    }
-
-    @Test
-    public void fromShortObject() {
-        final TypeMirror typeMirror = mockTypeMirror(null, "java.lang.Short");
-        assertEquals(SHORT_OBJECT, JavaType.from(typeMirror));
-    }
-
-    @Test
-    public void fromInteger() {
-        final TypeMirror typeMirror = mockTypeMirror(TypeKind.INT, null);
-        assertEquals(INTEGER, JavaType.from(typeMirror));
-    }
-
-    @Test
-    public void fromIntegerObject() {
-        final TypeMirror typeMirror = mockTypeMirror(null, "java.lang.Integer");
-        assertEquals(INTEGER_OBJECT, JavaType.from(typeMirror));
-    }
-
-    @Test
-    public void fromLong() {
-        final TypeMirror typeMirror = mockTypeMirror(TypeKind.LONG, null);
-        assertEquals(LONG, JavaType.from(typeMirror));
-    }
-
-    @Test
-    public void fromLongObject() {
-        final TypeMirror typeMirror = mockTypeMirror(null, "java.lang.Long");
-        assertEquals(LONG_OBJECT, JavaType.from(typeMirror));
-    }
-
-    @Test
-    public void fromFloat() {
-        final TypeMirror typeMirror = mockTypeMirror(TypeKind.FLOAT, null);
-        assertEquals(FLOAT, JavaType.from(typeMirror));
-    }
-
-    @Test
-    public void fromFloatObject() {
-        final TypeMirror typeMirror = mockTypeMirror(null, "java.lang.Float");
-        assertEquals(FLOAT_OBJECT, JavaType.from(typeMirror));
-    }
-
-    @Test
-    public void fromDouble() {
-        final TypeMirror typeMirror = mockTypeMirror(TypeKind.DOUBLE, null);
-        assertEquals(DOUBLE, JavaType.from(typeMirror));
-    }
-
-    @Test
-    public void fromDoubleObject() {
-        final TypeMirror typeMirror = mockTypeMirror(null, "java.lang.Double");
-        assertEquals(DOUBLE_OBJECT, JavaType.from(typeMirror));
-    }
-
-    @Test
-    public void fromString() {
-        final TypeMirror typeMirror = mockTypeMirror(null, "java.lang.String");
-        assertEquals(STRING, JavaType.from(typeMirror));
-    }
-}
diff --git a/storio-sqlite-annotation/build.gradle b/storio-sqlite-annotation/build.gradle
deleted file mode 100644
index 40ef981..0000000
--- a/storio-sqlite-annotation/build.gradle
+++ /dev/null
@@ -1,6 +0,0 @@
-apply plugin: 'java'
-
-targetCompatibility = '1.6'
-sourceCompatibility = '1.6'
-
-apply from: '../gradle/publish-java-lib.gradle'
\ No newline at end of file
diff --git a/storio-sqlite-annotation/gradle.properties b/storio-sqlite-annotation/gradle.properties
deleted file mode 100644
index 84a8e97..0000000
--- a/storio-sqlite-annotation/gradle.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-POM_NAME=sqlite-annotation
-POM_ARTIFACT_ID=sqlite-annotation
-POM_PACKAGING=jar
\ No newline at end of file
diff --git a/storio-sqlite-annotation/src/main/java/com/pushtorefresh/storio/sqlite/annotation/StorIOSQLiteColumn.java b/storio-sqlite-annotation/src/main/java/com/pushtorefresh/storio/sqlite/annotation/StorIOSQLiteColumn.java
deleted file mode 100644
index c8a7f01..0000000
--- a/storio-sqlite-annotation/src/main/java/com/pushtorefresh/storio/sqlite/annotation/StorIOSQLiteColumn.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.pushtorefresh.storio.sqlite.annotation;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-/**
- * Annotation for marking field of some class as SQLite column
- */
-@Target(FIELD)
-@Retention(RUNTIME) // we allow users to write reflection based code to work with annotation
-public @interface StorIOSQLiteColumn {
-
-    /**
-     * Required: specifies column name
-     *
-     * @return non-null column name
-     */
-    String name();
-
-    /**
-     * Optional: marks column as key, so it will be used to identify rows for Put and Delete Operations
-     *
-     * @return true if column is key, false otherwise
-     */
-    boolean key() default false;
-}
diff --git a/storio-sqlite-annotation/src/main/java/com/pushtorefresh/storio/sqlite/annotation/StorIOSQLiteType.java b/storio-sqlite-annotation/src/main/java/com/pushtorefresh/storio/sqlite/annotation/StorIOSQLiteType.java
deleted file mode 100644
index 2cbab7f..0000000
--- a/storio-sqlite-annotation/src/main/java/com/pushtorefresh/storio/sqlite/annotation/StorIOSQLiteType.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.pushtorefresh.storio.sqlite.annotation;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-/**
- * Annotation for marking class as StorIOSQLiteType to generate object mapping code
- */
-@Target(TYPE)
-@Retention(RUNTIME) // we allow users to write reflection based code to work with annotation
-public @interface StorIOSQLiteType {
-
-    /**
-     * Required: Specifies table name
-     *
-     * @return table name
-     */
-    String table();
-}
diff --git a/storio-sqlite-annotations-processor/build.gradle b/storio-sqlite-annotations-processor/build.gradle
new file mode 100644
index 0000000..72da066
--- /dev/null
+++ b/storio-sqlite-annotations-processor/build.gradle
@@ -0,0 +1,16 @@
+apply plugin: 'java'
+
+targetCompatibility = '1.6'
+sourceCompatibility = '1.6'
+
+dependencies {
+    compile libraries.storIOSQLiteAnnotation
+    compile libraries.intellijAnnotations
+    compile libraries.autoService
+    compile libraries.javaPoet
+
+    testCompile libraries.junit
+    testCompile libraries.mockitoCore
+}
+
+apply from: '../gradle/publish-java-lib.gradle'
\ No newline at end of file
diff --git a/storio-sqlite-annotations-processor/gradle.properties b/storio-sqlite-annotations-processor/gradle.properties
new file mode 100644
index 0000000..849be00
--- /dev/null
+++ b/storio-sqlite-annotations-processor/gradle.properties
@@ -0,0 +1,3 @@
+POM_NAME=sqlite-annotations-processor
+POM_ARTIFACT_ID=sqlite-annotations-processor
+POM_PACKAGING=jar
\ No newline at end of file
diff --git a/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/ProcessingException.java b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/ProcessingException.java
new file mode 100644
index 0000000..2cb2565
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/ProcessingException.java
@@ -0,0 +1,31 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor;
+
+import org.jetbrains.annotations.NotNull;
+
+import javax.lang.model.element.Element;
+
+/**
+ * Useful for logging errors from AnnotationProcessor,
+ * stores reference to {@link Element} that caused exception so IDE will show developer where is the problem
+ */
+public class ProcessingException extends RuntimeException {
+
+    /**
+     * Element that caused exception
+     */
+    @NotNull
+    private final Element element;
+
+    public ProcessingException(@NotNull Element element, @NotNull String message) {
+        super(message);
+        this.element = element;
+    }
+
+    /**
+     * @return non-null element that caused exception
+     */
+    @NotNull
+    public Element element() {
+        return element;
+    }
+}
diff --git a/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/StorIOSQLiteProcessor.java b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/StorIOSQLiteProcessor.java
new file mode 100644
index 0000000..95cc659
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/StorIOSQLiteProcessor.java
@@ -0,0 +1,331 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor;
+
+import com.google.auto.service.AutoService;
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn;
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType;
+import com.pushtorefresh.storio.sqlite.annotations.processor.generate.DeleteResolverGenerator;
+import com.pushtorefresh.storio.sqlite.annotations.processor.generate.GetResolverGenerator;
+import com.pushtorefresh.storio.sqlite.annotations.processor.generate.PutResolverGenerator;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteColumnMeta;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteTypeMeta;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.Messager;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
+
+import static javax.lang.model.element.ElementKind.CLASS;
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+/**
+ * Annotation processor for StorIOSQLite
+ * <p>
+ * It'll process annotations to generate StorIOSQLite Object-Mapping
+ * <p>
+ * Addition: Annotation Processor should work fast and be optimized because it's part of compilation
+ * We don't want to annoy developers, who use StorIO
+ */
+// Generate file with annotation processor declaration via another Annotation Processor!
+@AutoService(Processor.class)
+public class StorIOSQLiteProcessor extends AbstractProcessor {
+
+    private Filer filer;
+    private Elements elementUtils;
+    private Messager messager;
+
+    /**
+     * Processes class annotations
+     *
+     * @param roundEnvironment environment
+     * @return non-null unmodifiable map(element, typeMeta)
+     */
+    @NotNull
+    private static Map<TypeElement, StorIOSQLiteTypeMeta> processAnnotatedClasses(@NotNull final RoundEnvironment roundEnvironment, @NotNull final Elements elementUtils) {
+        final Set<? extends Element> elementsAnnotatedWithStorIOSQLiteType
+                = roundEnvironment.getElementsAnnotatedWith(StorIOSQLiteType.class);
+
+        final Map<TypeElement, StorIOSQLiteTypeMeta> results
+                = new HashMap<TypeElement, StorIOSQLiteTypeMeta>(elementsAnnotatedWithStorIOSQLiteType.size());
+
+        for (final Element annotatedElement : elementsAnnotatedWithStorIOSQLiteType) {
+            final TypeElement classElement = validateAnnotatedClass(annotatedElement);
+            final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = processAnnotatedClass(classElement, elementUtils);
+            results.put(classElement, storIOSQLiteTypeMeta);
+        }
+
+        return Collections.unmodifiableMap(results);
+    }
+
+    /**
+     * Checks that element annotated with {@link StorIOSQLiteType} satisfies all required conditions
+     *
+     * @param annotatedElement element annotated with {@link StorIOSQLiteType}
+     * @return {@link TypeElement} object
+     */
+    @NotNull
+    private static TypeElement validateAnnotatedClass(@NotNull final Element annotatedElement) {
+        // we expect here that annotatedElement is Class, annotation requires that via @Target
+        final TypeElement annotatedTypeElement = (TypeElement) annotatedElement;
+
+        if (annotatedTypeElement.getModifiers().contains(PRIVATE)) {
+            throw new ProcessingException(
+                    annotatedElement,
+                    StorIOSQLiteType.class.getSimpleName() + " can not be applied to private class: " + annotatedTypeElement.getQualifiedName()
+            );
+        }
+
+        return annotatedTypeElement;
+    }
+
+    /**
+     * Processes annotated class
+     *
+     * @param classElement type element annotated with {@link StorIOSQLiteType}
+     * @param elementUtils utils for working with elementUtils
+     * @return result of processing as {@link StorIOSQLiteTypeMeta}
+     */
+    @NotNull
+    private static StorIOSQLiteTypeMeta processAnnotatedClass(@NotNull TypeElement classElement, @NotNull Elements elementUtils) {
+        final StorIOSQLiteType storIOSQLiteType = classElement.getAnnotation(StorIOSQLiteType.class);
+
+        final String tableName = storIOSQLiteType.table();
+
+        if (tableName == null || tableName.length() == 0) {
+            throw new ProcessingException(
+                    classElement,
+                    "Table name of " + classElement.getQualifiedName() + " annotated with " + StorIOSQLiteType.class.getSimpleName() + " is null or empty"
+            );
+        }
+
+        final String simpleName = classElement.getSimpleName().toString();
+        final String packageName = elementUtils.getPackageOf(classElement).getQualifiedName().toString();
+
+        return new StorIOSQLiteTypeMeta(simpleName, packageName, storIOSQLiteType);
+    }
+
+    /**
+     * Processes fields annotated with {@link StorIOSQLiteColumn}
+     *
+     * @param roundEnvironment current processing environment
+     * @param annotatedClasses map of classes annotated with {@link StorIOSQLiteType}
+     */
+    private static void processAnnotatedFields(@NotNull final RoundEnvironment roundEnvironment, @NotNull Map<TypeElement, StorIOSQLiteTypeMeta> annotatedClasses) {
+        final Set<? extends Element> elementsAnnotatedWithStorIOSQLiteColumn
+                = roundEnvironment.getElementsAnnotatedWith(StorIOSQLiteColumn.class);
+
+        for (final Element annotatedFieldElement : elementsAnnotatedWithStorIOSQLiteColumn) {
+            validateAnnotatedField(annotatedFieldElement);
+            final StorIOSQLiteColumnMeta storIOSQLiteColumnMeta = processAnnotatedField(annotatedFieldElement);
+
+            final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = annotatedClasses.get(storIOSQLiteColumnMeta.enclosingElement);
+
+            if (storIOSQLiteTypeMeta == null) {
+                throw new ProcessingException(annotatedFieldElement, "Field marked with "
+                        + StorIOSQLiteColumn.class.getSimpleName()
+                        + " annotation should be placed in class marked by "
+                        + StorIOSQLiteType.class.getSimpleName()
+                        + " annotation"
+                );
+            }
+
+            // Put meta column info
+            // If class already contains column with same name -> throw exception
+            if (storIOSQLiteTypeMeta.columns.put(storIOSQLiteColumnMeta.storIOSQLiteColumn.name(), storIOSQLiteColumnMeta) != null) {
+                throw new ProcessingException(annotatedFieldElement, "Column name already used in this class");
+            }
+        }
+    }
+
+    //region Processing of annotated classes
+
+    /**
+     * Checks that element annotated with {@link StorIOSQLiteColumn} satisfies all required conditions
+     *
+     * @param annotatedField element annotated with {@link StorIOSQLiteColumn}
+     */
+    private static void validateAnnotatedField(@NotNull final Element annotatedField) {
+        // we expect here that annotatedElement is Field, annotation requires that via @Target
+
+        final Element enclosingElement = annotatedField.getEnclosingElement();
+
+        if (!enclosingElement.getKind().equals(CLASS)) {
+            throw new ProcessingException(
+                    annotatedField,
+                    "Please apply " + StorIOSQLiteType.class.getSimpleName() + " to fields of class: " + annotatedField.getSimpleName()
+            );
+        }
+
+        if (enclosingElement.getAnnotation(StorIOSQLiteType.class) == null) {
+            throw new ProcessingException(
+                    annotatedField,
+                    "Please annotate class " + enclosingElement.getSimpleName() + " with " + StorIOSQLiteType.class.getSimpleName()
+            );
+        }
+
+        if (annotatedField.getModifiers().contains(PRIVATE)) {
+            throw new ProcessingException(
+                    annotatedField,
+                    StorIOSQLiteColumn.class.getSimpleName() + " can not be applied to private field: " + annotatedField.getSimpleName()
+            );
+        }
+
+        if (annotatedField.getModifiers().contains(FINAL)) {
+            throw new ProcessingException(
+                    annotatedField,
+                    StorIOSQLiteColumn.class.getSimpleName() + " can not be applied to final field: " + annotatedField.getSimpleName()
+            );
+        }
+    }
+
+    /**
+     * Processes annotated field and returns result of processing or throws exception
+     *
+     * @param annotatedField field that was annotated with {@link StorIOSQLiteColumn}
+     * @return non-null {@link StorIOSQLiteColumnMeta} with meta information about field
+     */
+    @NotNull
+    private static StorIOSQLiteColumnMeta processAnnotatedField(@NotNull final Element annotatedField) {
+        final JavaType javaType;
+
+        try {
+            javaType = JavaType.from(annotatedField.asType());
+        } catch (Exception e) {
+            throw new ProcessingException(annotatedField, "Unsupported type of field for "
+                    + StorIOSQLiteColumn.class.getSimpleName()
+                    + " annotation, if you need to serialize/deserialize field of that type "
+                    + "-> please write your own resolver: "
+                    + e.getMessage()
+            );
+        }
+
+        final StorIOSQLiteColumn storIOSQLiteColumn = annotatedField.getAnnotation(StorIOSQLiteColumn.class);
+
+        final String columnName = storIOSQLiteColumn.name();
+
+        if (columnName == null || columnName.length() == 0) {
+            throw new ProcessingException(annotatedField, "Column name is null or empty");
+        }
+
+        return new StorIOSQLiteColumnMeta(
+                annotatedField.getEnclosingElement(),
+                annotatedField,
+                annotatedField.getSimpleName().toString(),
+                javaType,
+                storIOSQLiteColumn
+        );
+    }
+
+    private static void validateAnnotatedClassesAndColumns(@NotNull Map<TypeElement, StorIOSQLiteTypeMeta> annotatedClasses) {
+        // check that each annotated class has columns with at least one key column
+        for (Map.Entry<TypeElement, StorIOSQLiteTypeMeta> annotatedClass : annotatedClasses.entrySet()) {
+            if (annotatedClass.getValue().columns.size() == 0) {
+                throw new ProcessingException(annotatedClass.getKey(),
+                        "Class marked with "
+                                + StorIOSQLiteType.class.getSimpleName()
+                                + " annotation should have at least one field marked with "
+                                + StorIOSQLiteColumn.class.getSimpleName()
+                                + " annotation");
+            }
+
+            boolean hasAtLeastOneKeyColumn = false;
+
+            for (StorIOSQLiteColumnMeta columnMeta : annotatedClass.getValue().columns.values()) {
+                if (columnMeta.storIOSQLiteColumn.key()) {
+                    hasAtLeastOneKeyColumn = true;
+                    break;
+                }
+            }
+
+            if (!hasAtLeastOneKeyColumn) {
+                throw new ProcessingException(annotatedClass.getKey(),
+                        "Class marked with "
+                                + StorIOSQLiteType.class.getSimpleName()
+                                + " annotation should have at least one KEY field marked with "
+                                + StorIOSQLiteColumn.class.getSimpleName() + " annotation");
+            }
+        }
+    }
+
+    //endregion
+
+    //region Processing of annotated fields
+
+    @Override
+    public synchronized void init(ProcessingEnvironment processingEnv) {
+        super.init(processingEnv);
+        filer = processingEnv.getFiler();
+        elementUtils = processingEnv.getElementUtils(); // why class name is "Elements" but method "getElementUtils()", OKAY..
+        messager = processingEnv.getMessager();
+    }
+
+    @Override
+    public Set<String> getSupportedAnnotationTypes() {
+        final Set<String> supportedAnnotations = new HashSet<String>(2);
+
+        supportedAnnotations.add(StorIOSQLiteType.class.getCanonicalName());
+        supportedAnnotations.add(StorIOSQLiteColumn.class.getCanonicalName());
+
+        return supportedAnnotations;
+    }
+
+    @Override
+    public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latestSupported();
+    }
+
+    //endregion
+
+    /**
+     * For those who don't familiar with Annotation Processing API — this is the main method of Annotation Processor lifecycle
+     * <p>
+     * It will be after Java Compiler will find lang elements annotated with annotations from {@link #getSupportedAnnotationTypes()}
+     *
+     * @param annotations set of annotations
+     * @param roundEnv    environment of current processing round
+     * @return true if annotation processor should not be invoked in next rounds of annotation processing, false otherwise
+     */
+    @Override
+    public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
+        try {
+            final Map<TypeElement, StorIOSQLiteTypeMeta> annotatedClasses
+                    = processAnnotatedClasses(roundEnv, elementUtils);
+
+            processAnnotatedFields(roundEnv, annotatedClasses);
+
+            validateAnnotatedClassesAndColumns(annotatedClasses);
+
+            final PutResolverGenerator putResolverGenerator = new PutResolverGenerator();
+            final GetResolverGenerator getResolverGenerator = new GetResolverGenerator();
+            final DeleteResolverGenerator deleteResolverGenerator = new DeleteResolverGenerator();
+
+            for (StorIOSQLiteTypeMeta storIOSQLiteTypeMeta : annotatedClasses.values()) {
+                putResolverGenerator.generateJavaFile(storIOSQLiteTypeMeta).writeTo(filer);
+                getResolverGenerator.generateJavaFile(storIOSQLiteTypeMeta).writeTo(filer);
+                deleteResolverGenerator.generateJavaFile(storIOSQLiteTypeMeta).writeTo(filer);
+            }
+        } catch (ProcessingException e) {
+            messager.printMessage(ERROR, e.getMessage(), e.element());
+        } catch (Exception e) {
+            messager.printMessage(ERROR, "Problem occurred with StorIOSQLiteProcessor: " + e.getMessage());
+        }
+
+        return true;
+    }
+}
diff --git a/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/Common.java b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/Common.java
new file mode 100644
index 0000000..27970dd
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/Common.java
@@ -0,0 +1,10 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor.generate;
+
+import com.squareup.javapoet.ClassName;
+
+class Common {
+
+    static final ClassName ANDROID_NON_NULL_ANNOTATION_CLASS_NAME = ClassName.get("android.support.annotation", "NonNull");
+
+    static final String INDENT = "    "; // 4 spaces
+}
diff --git a/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/DeleteResolverGenerator.java b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/DeleteResolverGenerator.java
new file mode 100644
index 0000000..0bc564f
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/DeleteResolverGenerator.java
@@ -0,0 +1,62 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor.generate;
+
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteTypeMeta;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeSpec;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+import static com.pushtorefresh.storio.sqlite.annotations.processor.generate.Common.ANDROID_NON_NULL_ANNOTATION_CLASS_NAME;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.generate.Common.INDENT;
+import static javax.lang.model.element.Modifier.PROTECTED;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+public class DeleteResolverGenerator {
+
+    @NotNull
+    public JavaFile generateJavaFile(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta) {
+        final ClassName storIOSQLiteTypeClassName = ClassName.get(storIOSQLiteTypeMeta.packageName, storIOSQLiteTypeMeta.simpleName);
+
+        final TypeSpec deleteResolver = TypeSpec.classBuilder(storIOSQLiteTypeMeta.simpleName + "StorIOSQLiteDeleteResolver")
+                .addJavadoc("Generated resolver for Delete Operation\n")
+                .addModifiers(PUBLIC)
+                .superclass(ParameterizedTypeName.get(ClassName.get("com.pushtorefresh.storio.sqlite.operations.delete", "DefaultDeleteResolver"), storIOSQLiteTypeClassName))
+                .addMethod(createMapToDeleteQueryMethodSpec(storIOSQLiteTypeMeta, storIOSQLiteTypeClassName))
+                .build();
+
+        return JavaFile
+                .builder(storIOSQLiteTypeMeta.packageName, deleteResolver)
+                .indent(INDENT)
+                .build();
+    }
+
+    @NotNull
+    MethodSpec createMapToDeleteQueryMethodSpec(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta, @NotNull ClassName storIOSQLiteTypeClassName) {
+        final Map<String, String> where = QueryGenerator.createWhere(storIOSQLiteTypeMeta, "object");
+
+        return MethodSpec.methodBuilder("mapToDeleteQuery")
+                .addJavadoc("{@inheritDoc}\n")
+                .addAnnotation(Override.class)
+                .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
+                .addModifiers(PROTECTED)
+                .returns(ClassName.get("com.pushtorefresh.storio.sqlite.queries", "DeleteQuery"))
+                .addParameter(ParameterSpec.builder(storIOSQLiteTypeClassName, "object")
+                        .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
+                        .build())
+                .addCode("return DeleteQuery.builder()\n" +
+                                INDENT + ".table($S)\n" +
+                                INDENT + ".where($S)\n" +
+                                INDENT + ".whereArgs($L)\n" +
+                                INDENT + ".build();\n",
+                        storIOSQLiteTypeMeta.storIOSQLiteType.table(),
+                        where.get(QueryGenerator.WHERE_CLAUSE),
+                        where.get(QueryGenerator.WHERE_ARGS))
+                .build();
+    }
+}
diff --git a/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/GetResolverGenerator.java b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/GetResolverGenerator.java
new file mode 100644
index 0000000..54639ce
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/GetResolverGenerator.java
@@ -0,0 +1,100 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor.generate;
+
+import com.pushtorefresh.storio.sqlite.annotations.processor.ProcessingException;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteColumnMeta;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteTypeMeta;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeSpec;
+
+import org.jetbrains.annotations.NotNull;
+
+import static com.pushtorefresh.storio.sqlite.annotations.processor.generate.Common.ANDROID_NON_NULL_ANNOTATION_CLASS_NAME;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.generate.Common.INDENT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.BOOLEAN;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.BOOLEAN_OBJECT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.DOUBLE;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.DOUBLE_OBJECT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.FLOAT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.FLOAT_OBJECT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.INTEGER;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.INTEGER_OBJECT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.LONG;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.LONG_OBJECT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.SHORT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.SHORT_OBJECT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.STRING;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+public class GetResolverGenerator {
+
+    @NotNull
+    public JavaFile generateJavaFile(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta) {
+        final ClassName storIOSQLiteTypeClassName = ClassName.get(storIOSQLiteTypeMeta.packageName, storIOSQLiteTypeMeta.simpleName);
+
+        final TypeSpec getResolver = TypeSpec.classBuilder(storIOSQLiteTypeMeta.simpleName + "StorIOSQLiteGetResolver")
+                .addJavadoc("Generated resolver for Get Operation\n")
+                .addModifiers(PUBLIC)
+                .superclass(ParameterizedTypeName.get(ClassName.get("com.pushtorefresh.storio.sqlite.operations.get", "DefaultGetResolver"), storIOSQLiteTypeClassName))
+                .addMethod(createMapFromCursorMethodSpec(storIOSQLiteTypeMeta, storIOSQLiteTypeClassName))
+                .build();
+
+        return JavaFile
+                .builder(storIOSQLiteTypeMeta.packageName, getResolver)
+                .indent(INDENT)
+                .build();
+    }
+
+    @NotNull
+    MethodSpec createMapFromCursorMethodSpec(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta, @NotNull ClassName storIOSQLiteTypeClassName) {
+        final MethodSpec.Builder builder = MethodSpec.methodBuilder("mapFromCursor")
+                .addJavadoc("{@inheritDoc}\n")
+                .addAnnotation(Override.class)
+                .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
+                .addModifiers(PUBLIC)
+                .returns(storIOSQLiteTypeClassName)
+                .addParameter(ParameterSpec.builder(ClassName.get("android.database", "Cursor"), "cursor")
+                        .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
+                        .build())
+                .addStatement("$T object = new $T()", storIOSQLiteTypeClassName, storIOSQLiteTypeClassName)
+                .addCode("\n");
+
+        for (final StorIOSQLiteColumnMeta columnMeta : storIOSQLiteTypeMeta.columns.values()) {
+            final String columnIndex = "cursor.getColumnIndex(\"" + columnMeta.storIOSQLiteColumn.name() + "\")";
+
+            final String getFromCursor;
+
+            final JavaType javaType = columnMeta.javaType;
+
+            if (javaType == BOOLEAN || javaType == BOOLEAN_OBJECT) {
+                getFromCursor = "getInt(" + columnIndex + ") == 1";
+            } else if (javaType == SHORT || javaType == SHORT_OBJECT) {
+                getFromCursor = "getShort(" + columnIndex + ")";
+            } else if (javaType == INTEGER || javaType == INTEGER_OBJECT) {
+                getFromCursor = "getInt(" + columnIndex + ")";
+            } else if (javaType == LONG || javaType == LONG_OBJECT) {
+                getFromCursor = "getLong(" + columnIndex + ")";
+            } else if (javaType == FLOAT || javaType == FLOAT_OBJECT) {
+                getFromCursor = "getFloat(" + columnIndex + ")";
+            } else if (javaType == DOUBLE || javaType == DOUBLE_OBJECT) {
+                getFromCursor = "getDouble(" + columnIndex + ")";
+            } else if (javaType == STRING) {
+                getFromCursor = "getString(" + columnIndex + ")";
+            } else {
+                throw new ProcessingException(columnMeta.element, "Can not generate GetResolver for field");
+            }
+
+            builder
+                    .addStatement("object.$L = cursor.$L", columnMeta.fieldName, getFromCursor);
+        }
+
+        return builder
+                .addCode("\n")
+                .addStatement("return object")
+                .build();
+    }
+}
diff --git a/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/PutResolverGenerator.java b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/PutResolverGenerator.java
new file mode 100644
index 0000000..95f348a
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/PutResolverGenerator.java
@@ -0,0 +1,111 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor.generate;
+
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteColumnMeta;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteTypeMeta;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeSpec;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Map;
+
+import static com.pushtorefresh.storio.sqlite.annotations.processor.generate.Common.ANDROID_NON_NULL_ANNOTATION_CLASS_NAME;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.generate.Common.INDENT;
+import static javax.lang.model.element.Modifier.PROTECTED;
+import static javax.lang.model.element.Modifier.PUBLIC;
+
+public class PutResolverGenerator {
+
+    @NotNull
+    public JavaFile generateJavaFile(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta) {
+        final ClassName storIOSQLiteTypeClassName = ClassName.get(storIOSQLiteTypeMeta.packageName, storIOSQLiteTypeMeta.simpleName);
+
+        final TypeSpec putResolver = TypeSpec.classBuilder(storIOSQLiteTypeMeta.simpleName + "StorIOSQLitePutResolver")
+                .addJavadoc("Generated resolver for Put Operation\n")
+                .addModifiers(PUBLIC)
+                .superclass(ParameterizedTypeName.get(ClassName.get("com.pushtorefresh.storio.sqlite.operations.put", "DefaultPutResolver"), storIOSQLiteTypeClassName))
+                .addMethod(createMapToInsertQueryMethodSpec(storIOSQLiteTypeMeta, storIOSQLiteTypeClassName))
+                .addMethod(createMapToUpdateQueryMethodSpec(storIOSQLiteTypeMeta, storIOSQLiteTypeClassName))
+                .addMethod(createMapToContentValuesMethodSpec(storIOSQLiteTypeMeta, storIOSQLiteTypeClassName))
+                .build();
+
+        return JavaFile
+                .builder(storIOSQLiteTypeMeta.packageName, putResolver)
+                .indent(INDENT)
+                .build();
+    }
+
+    @NotNull
+    MethodSpec createMapToInsertQueryMethodSpec(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta, @NotNull ClassName storIOSQLiteTypeClassName) {
+        return MethodSpec.methodBuilder("mapToInsertQuery")
+                .addJavadoc("{@inheritDoc}\n")
+                .addAnnotation(Override.class)
+                .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
+                .addModifiers(PROTECTED)
+                .returns(ClassName.get("com.pushtorefresh.storio.sqlite.queries", "InsertQuery"))
+                .addParameter(ParameterSpec.builder(storIOSQLiteTypeClassName, "object")
+                        .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
+                        .build())
+                .addCode("return InsertQuery.builder()\n" +
+                                INDENT + ".table($S)\n" +
+                                INDENT + ".build();\n",
+                        storIOSQLiteTypeMeta.storIOSQLiteType.table())
+                .build();
+    }
+
+    @NotNull
+    MethodSpec createMapToUpdateQueryMethodSpec(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta, @NotNull ClassName storIOSQLiteTypeClassName) {
+        final Map<String, String> where = QueryGenerator.createWhere(storIOSQLiteTypeMeta, "object");
+
+        return MethodSpec.methodBuilder("mapToUpdateQuery")
+                .addJavadoc("{@inheritDoc}\n")
+                .addAnnotation(Override.class)
+                .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
+                .addModifiers(PROTECTED)
+                .returns(ClassName.get("com.pushtorefresh.storio.sqlite.queries", "UpdateQuery"))
+                .addParameter(ParameterSpec.builder(storIOSQLiteTypeClassName, "object")
+                        .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
+                        .build())
+                .addCode("return UpdateQuery.builder()\n" +
+                                INDENT + ".table($S)\n" +
+                                INDENT + ".where($S)\n" +
+                                INDENT + ".whereArgs($L)\n" +
+                                INDENT + ".build();\n",
+                        storIOSQLiteTypeMeta.storIOSQLiteType.table(),
+                        where.get(QueryGenerator.WHERE_CLAUSE),
+                        where.get(QueryGenerator.WHERE_ARGS))
+                .build();
+    }
+
+    @NotNull
+    MethodSpec createMapToContentValuesMethodSpec(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta, @NotNull ClassName storIOSQLiteTypeClassName) {
+        final MethodSpec.Builder builder = MethodSpec.methodBuilder("mapToContentValues")
+                .addJavadoc("{@inheritDoc}\n")
+                .addAnnotation(Override.class)
+                .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
+                .addModifiers(PUBLIC)
+                .returns(ClassName.get("android.content", "ContentValues"))
+                .addParameter(ParameterSpec.builder(storIOSQLiteTypeClassName, "object")
+                        .addAnnotation(ANDROID_NON_NULL_ANNOTATION_CLASS_NAME)
+                        .build())
+                .addStatement("ContentValues contentValues = new ContentValues($L)", storIOSQLiteTypeMeta.columns.size())
+                .addCode("\n");
+
+        for (StorIOSQLiteColumnMeta columnMeta : storIOSQLiteTypeMeta.columns.values()) {
+            builder.addStatement(
+                    "contentValues.put($S, $L)",
+                    columnMeta.storIOSQLiteColumn.name(),
+                    "object." + columnMeta.fieldName
+            );
+        }
+
+        return builder
+                .addCode("\n")
+                .addStatement("return contentValues")
+                .build();
+    }
+}
diff --git a/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/QueryGenerator.java b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/QueryGenerator.java
new file mode 100644
index 0000000..7445d85
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/QueryGenerator.java
@@ -0,0 +1,63 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor.generate;
+
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteColumnMeta;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteTypeMeta;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public class QueryGenerator {
+
+    public static final String WHERE_CLAUSE = "where";
+    public static final String WHERE_ARGS = "whereArgs";
+
+    @NotNull
+    public static Map<String, String> createWhere(@NotNull StorIOSQLiteTypeMeta storIOSQLiteTypeMeta, @NotNull String varName) {
+        final StringBuilder whereClause = new StringBuilder();
+        final StringBuilder whereArgs = new StringBuilder();
+
+        int i = 0;
+
+        for (final StorIOSQLiteColumnMeta columnMeta : storIOSQLiteTypeMeta.columns.values()) {
+            if (columnMeta.storIOSQLiteColumn.key()) {
+                if (i == 0) {
+                    whereClause
+                            .append(columnMeta.storIOSQLiteColumn.name())
+                            .append(" = ?");
+
+                    whereArgs
+                            .append(varName)
+                            .append(".")
+                            .append(columnMeta.fieldName);
+                } else {
+                    whereClause
+                            .append(" AND ")
+                            .append(columnMeta.storIOSQLiteColumn.name())
+                            .append(" = ?");
+
+                    whereArgs
+                            .append(", ")
+                            .append(varName)
+                            .append(".")
+                            .append(columnMeta.fieldName);
+                }
+
+                i++;
+            }
+        }
+
+        if (whereClause.length() == 0 || whereArgs.length() == 0) {
+            return Collections.emptyMap();
+        } else {
+            final Map<String, String> result = new HashMap<String, String>(2);
+
+            result.put(WHERE_CLAUSE, whereClause.toString()); // example: "email = ? AND user_id = ?"
+            result.put(WHERE_ARGS, whereArgs.toString()); // example: "object.email, object.userId"
+
+            return result;
+        }
+    }
+}
diff --git a/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/JavaType.java b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/JavaType.java
new file mode 100644
index 0000000..e876eb4
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/JavaType.java
@@ -0,0 +1,59 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor.introspection;
+
+import org.jetbrains.annotations.NotNull;
+
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+public enum JavaType {
+
+    BOOLEAN,
+    BOOLEAN_OBJECT,
+    SHORT,
+    SHORT_OBJECT,
+    INTEGER,
+    INTEGER_OBJECT,
+    LONG,
+    LONG_OBJECT,
+    FLOAT,
+    FLOAT_OBJECT,
+    DOUBLE,
+    DOUBLE_OBJECT,
+    STRING;
+
+    @NotNull
+    public static JavaType from(@NotNull TypeMirror typeMirror) {
+        final TypeKind typeKind = typeMirror.getKind();
+        final String typeName = typeMirror.toString(); // fqn of type, for example java.lang.String
+
+        if (typeKind == TypeKind.BOOLEAN) {
+            return BOOLEAN;
+        } else if ("java.lang.Boolean".equals(typeName)) {
+            return BOOLEAN_OBJECT;
+        } else if (typeKind == TypeKind.SHORT) {
+            return SHORT;
+        } else if ("java.lang.Short".equals(typeName)) {
+            return SHORT_OBJECT;
+        } else if (typeKind == TypeKind.INT) {
+            return INTEGER;
+        } else if ("java.lang.Integer".equals(typeName)) {
+            return INTEGER_OBJECT;
+        } else if (typeKind == TypeKind.LONG) {
+            return LONG;
+        } else if ("java.lang.Long".equals(typeName)) {
+            return LONG_OBJECT;
+        } else if (typeKind == TypeKind.FLOAT) {
+            return FLOAT;
+        } else if ("java.lang.Float".equals(typeName)) {
+            return FLOAT_OBJECT;
+        } else if (typeKind == TypeKind.DOUBLE) {
+            return DOUBLE;
+        } else if ("java.lang.Double".equals(typeName)) {
+            return DOUBLE_OBJECT;
+        } else if ("java.lang.String".equals(typeName)) {
+            return STRING;
+        } else {
+            throw new IllegalArgumentException("Unsupported type: " + typeMirror);
+        }
+    }
+}
diff --git a/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/StorIOSQLiteColumnMeta.java b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/StorIOSQLiteColumnMeta.java
new file mode 100644
index 0000000..9513e73
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/StorIOSQLiteColumnMeta.java
@@ -0,0 +1,68 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor.introspection;
+
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn;
+
+import org.jetbrains.annotations.NotNull;
+
+import javax.lang.model.element.Element;
+
+public class StorIOSQLiteColumnMeta {
+
+    @NotNull
+    public final Element enclosingElement;
+
+    @NotNull
+    public final Element element;
+
+    @NotNull
+    public final String fieldName;
+
+    @NotNull
+    public final JavaType javaType;
+
+    @NotNull
+    public final StorIOSQLiteColumn storIOSQLiteColumn;
+
+    public StorIOSQLiteColumnMeta(@NotNull Element enclosingElement, @NotNull Element element, @NotNull String fieldName, @NotNull JavaType javaType, @NotNull StorIOSQLiteColumn storIOSQLiteColumn) {
+        this.enclosingElement = enclosingElement;
+        this.element = element;
+        this.fieldName = fieldName;
+        this.javaType = javaType;
+        this.storIOSQLiteColumn = storIOSQLiteColumn;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        StorIOSQLiteColumnMeta that = (StorIOSQLiteColumnMeta) o;
+
+        if (!enclosingElement.equals(that.enclosingElement)) return false;
+        if (!element.equals(that.element)) return false;
+        if (!fieldName.equals(that.fieldName)) return false;
+        if (javaType != that.javaType) return false;
+        return storIOSQLiteColumn.equals(that.storIOSQLiteColumn);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = enclosingElement.hashCode();
+        result = 31 * result + element.hashCode();
+        result = 31 * result + fieldName.hashCode();
+        result = 31 * result + javaType.hashCode();
+        result = 31 * result + storIOSQLiteColumn.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "StorIOSQLiteColumnMeta{" +
+                "enclosingElement=" + enclosingElement +
+                ", element=" + element +
+                ", fieldName='" + fieldName + '\'' +
+                ", javaType=" + javaType +
+                ", storIOSQLiteColumn=" + storIOSQLiteColumn +
+                '}';
+    }
+}
diff --git a/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/StorIOSQLiteTypeMeta.java b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/StorIOSQLiteTypeMeta.java
new file mode 100644
index 0000000..7e9835c
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/main/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/StorIOSQLiteTypeMeta.java
@@ -0,0 +1,64 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor.introspection;
+
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class StorIOSQLiteTypeMeta {
+
+    @NotNull
+    public final String simpleName;
+
+    @NotNull
+    public final String packageName;
+
+    @NotNull
+    public final StorIOSQLiteType storIOSQLiteType;
+
+    /**
+     * Yep, this is MODIFIABLE Map, please use it carefully
+     */
+    @NotNull
+    public final Map<String, StorIOSQLiteColumnMeta> columns = new HashMap<String, StorIOSQLiteColumnMeta>();
+
+    public StorIOSQLiteTypeMeta(@NotNull String simpleName, @NotNull String packageName, @NotNull StorIOSQLiteType storIOSQLiteType) {
+        this.simpleName = simpleName;
+        this.packageName = packageName;
+        this.storIOSQLiteType = storIOSQLiteType;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        StorIOSQLiteTypeMeta that = (StorIOSQLiteTypeMeta) o;
+
+        if (!simpleName.equals(that.simpleName)) return false;
+        if (!packageName.equals(that.packageName)) return false;
+        if (!storIOSQLiteType.equals(that.storIOSQLiteType)) return false;
+        return columns.equals(that.columns);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = simpleName.hashCode();
+        result = 31 * result + packageName.hashCode();
+        result = 31 * result + storIOSQLiteType.hashCode();
+        result = 31 * result + columns.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "StorIOSQLiteTypeMeta{" +
+                "simpleName='" + simpleName + '\'' +
+                ", packageName='" + packageName + '\'' +
+                ", storIOSQLiteType=" + storIOSQLiteType +
+                ", columns=" + columns +
+                '}';
+    }
+}
diff --git a/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/DeleteResolverGeneratorTest.java b/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/DeleteResolverGeneratorTest.java
new file mode 100644
index 0000000..2925212
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/DeleteResolverGeneratorTest.java
@@ -0,0 +1,82 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor.generate;
+
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn;
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteColumnMeta;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteTypeMeta;
+import com.squareup.javapoet.JavaFile;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class DeleteResolverGeneratorTest {
+
+    @Test
+    public void generateJavaFile() throws IOException {
+        final StorIOSQLiteType storIOSQLiteType = mock(StorIOSQLiteType.class);
+
+        when(storIOSQLiteType.table()).thenReturn("test_table");
+
+        final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = new StorIOSQLiteTypeMeta(
+                "TestItem",
+                "com.test",
+                storIOSQLiteType
+        );
+
+        final StorIOSQLiteColumn storIOSQLiteColumn1 = mock(StorIOSQLiteColumn.class);
+        when(storIOSQLiteColumn1.name()).thenReturn("column1");
+        final StorIOSQLiteColumnMeta storIOSQLiteColumnMeta1 = new StorIOSQLiteColumnMeta(
+                null,
+                null,
+                "field1",
+                null,
+                storIOSQLiteColumn1
+        );
+        storIOSQLiteTypeMeta.columns.put("column1", storIOSQLiteColumnMeta1);
+
+        final StorIOSQLiteColumn storIOSQLiteColumn2 = mock(StorIOSQLiteColumn.class);
+        when(storIOSQLiteColumn2.name()).thenReturn("column2");
+        final StorIOSQLiteColumnMeta storIOSQLiteColumnMeta2 = new StorIOSQLiteColumnMeta(
+                null,
+                null,
+                "field2",
+                null,
+                storIOSQLiteColumn2
+        );
+        storIOSQLiteTypeMeta.columns.put("column2", storIOSQLiteColumnMeta2);
+
+        final JavaFile javaFile = new DeleteResolverGenerator().generateJavaFile(storIOSQLiteTypeMeta);
+        final StringBuilder out = new StringBuilder();
+        javaFile.writeTo(out);
+
+        assertEquals("package com.test;\n" +
+                "\n" +
+                "import android.support.annotation.NonNull;\n" +
+                "import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver;\n" +
+                "import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;\n" +
+                "import java.lang.Override;\n" +
+                "\n" +
+                "/**\n" +
+                " * Generated resolver for Delete Operation\n" +
+                " */\n" +
+                "public class TestItemStorIOSQLiteDeleteResolver extends DefaultDeleteResolver<TestItem> {\n" +
+                "    /**\n" +
+                "     * {@inheritDoc}\n" +
+                "     */\n" +
+                "    @Override\n" +
+                "    @NonNull\n" +
+                "    protected DeleteQuery mapToDeleteQuery(@NonNull TestItem object) {\n" +
+                "        return DeleteQuery.builder()\n" +
+                "            .table(\"test_table\")\n" +
+                "            .where(null)\n" +
+                "            .whereArgs(null)\n" +
+                "            .build();\n" +
+                "    }\n" +
+                "}\n", out.toString());
+    }
+}
diff --git a/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/GetResolverGeneratorTest.java b/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/GetResolverGeneratorTest.java
new file mode 100644
index 0000000..0c16c51
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/GetResolverGeneratorTest.java
@@ -0,0 +1,84 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor.generate;
+
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn;
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteColumnMeta;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteTypeMeta;
+import com.squareup.javapoet.JavaFile;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class GetResolverGeneratorTest {
+
+    @Test
+    public void generateJavaFileTest() throws IOException {
+        final StorIOSQLiteType storIOSQLiteType = mock(StorIOSQLiteType.class);
+
+        when(storIOSQLiteType.table()).thenReturn("test_table");
+
+        final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = new StorIOSQLiteTypeMeta(
+                "TestItem",
+                "com.test",
+                storIOSQLiteType
+        );
+
+        final StorIOSQLiteColumn storIOSQLiteColumn1 = mock(StorIOSQLiteColumn.class);
+        when(storIOSQLiteColumn1.name()).thenReturn("column1");
+        final StorIOSQLiteColumnMeta storIOSQLiteColumnMeta1 = new StorIOSQLiteColumnMeta(
+                null,
+                null,
+                "field1",
+                JavaType.BOOLEAN,
+                storIOSQLiteColumn1
+        );
+        storIOSQLiteTypeMeta.columns.put("column1", storIOSQLiteColumnMeta1);
+
+        final StorIOSQLiteColumn storIOSQLiteColumn2 = mock(StorIOSQLiteColumn.class);
+        when(storIOSQLiteColumn2.name()).thenReturn("column2");
+        final StorIOSQLiteColumnMeta storIOSQLiteColumnMeta2 = new StorIOSQLiteColumnMeta(
+                null,
+                null,
+                "field2",
+                JavaType.STRING,
+                storIOSQLiteColumn2
+        );
+        storIOSQLiteTypeMeta.columns.put("column2", storIOSQLiteColumnMeta2);
+
+        final JavaFile javaFile = new GetResolverGenerator().generateJavaFile(storIOSQLiteTypeMeta);
+        final StringBuilder out = new StringBuilder();
+        javaFile.writeTo(out);
+
+        assertEquals("package com.test;\n" +
+                "\n" +
+                "import android.database.Cursor;\n" +
+                "import android.support.annotation.NonNull;\n" +
+                "import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver;\n" +
+                "import java.lang.Override;\n" +
+                "\n" +
+                "/**\n" +
+                " * Generated resolver for Get Operation\n" +
+                " */\n" +
+                "public class TestItemStorIOSQLiteGetResolver extends DefaultGetResolver<TestItem> {\n" +
+                "    /**\n" +
+                "     * {@inheritDoc}\n" +
+                "     */\n" +
+                "    @Override\n" +
+                "    @NonNull\n" +
+                "    public TestItem mapFromCursor(@NonNull Cursor cursor) {\n" +
+                "        TestItem object = new TestItem();\n" +
+                "\n" +
+                "        object.field1 = cursor.getInt(cursor.getColumnIndex(\"column1\")) == 1;\n" +
+                "        object.field2 = cursor.getString(cursor.getColumnIndex(\"column2\"));\n" +
+                "\n" +
+                "        return object;\n" +
+                "    }\n" +
+                "}\n", out.toString());
+    }
+}
diff --git a/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/PutResolverGeneratorTest.java b/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/PutResolverGeneratorTest.java
new file mode 100644
index 0000000..e74b92f
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/PutResolverGeneratorTest.java
@@ -0,0 +1,109 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor.generate;
+
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn;
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteColumnMeta;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteTypeMeta;
+import com.squareup.javapoet.JavaFile;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class PutResolverGeneratorTest {
+
+    @Test
+    public void generateJavaFile() throws IOException {
+        final PutResolverGenerator putResolverGenerator = new PutResolverGenerator();
+
+        final StorIOSQLiteType storIOSQLiteType = mock(StorIOSQLiteType.class);
+
+        when(storIOSQLiteType.table()).thenReturn("test_table");
+
+        final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = new StorIOSQLiteTypeMeta("TestItem", "com.test", storIOSQLiteType);
+
+        final StorIOSQLiteColumn storIOSQLiteColumn1 = mock(StorIOSQLiteColumn.class);
+        when(storIOSQLiteColumn1.name()).thenReturn("column1");
+        when(storIOSQLiteColumn1.key()).thenReturn(true);
+        final StorIOSQLiteColumnMeta storIOSQLiteColumnMeta1 = new StorIOSQLiteColumnMeta(
+                null,
+                null,
+                "column1Field",
+                null,
+                storIOSQLiteColumn1
+        );
+        storIOSQLiteTypeMeta.columns.put("column1", storIOSQLiteColumnMeta1);
+
+        final StorIOSQLiteColumn storIOSQLiteColumn2 = mock(StorIOSQLiteColumn.class);
+        when(storIOSQLiteColumn2.name()).thenReturn("column2");
+        when(storIOSQLiteColumn2.key()).thenReturn(false);
+        final StorIOSQLiteColumnMeta storIOSQLiteColumnMeta2 = new StorIOSQLiteColumnMeta(
+                null,
+                null,
+                "column2Field",
+                null,
+                storIOSQLiteColumn2
+        );
+        storIOSQLiteTypeMeta.columns.put("column2", storIOSQLiteColumnMeta2);
+
+        final JavaFile javaFile = putResolverGenerator.generateJavaFile(storIOSQLiteTypeMeta);
+        final StringBuilder out = new StringBuilder();
+        javaFile.writeTo(out);
+
+        assertEquals("package com.test;\n" +
+                "\n" +
+                "import android.content.ContentValues;\n" +
+                "import android.support.annotation.NonNull;\n" +
+                "import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver;\n" +
+                "import com.pushtorefresh.storio.sqlite.queries.InsertQuery;\n" +
+                "import com.pushtorefresh.storio.sqlite.queries.UpdateQuery;\n" +
+                "import java.lang.Override;\n" +
+                "\n" +
+                "/**\n" +
+                " * Generated resolver for Put Operation\n" +
+                " */\n" +
+                "public class TestItemStorIOSQLitePutResolver extends DefaultPutResolver<TestItem> {\n" +
+                "    /**\n" +
+                "     * {@inheritDoc}\n" +
+                "     */\n" +
+                "    @Override\n" +
+                "    @NonNull\n" +
+                "    protected InsertQuery mapToInsertQuery(@NonNull TestItem object) {\n" +
+                "        return InsertQuery.builder()\n" +
+                "            .table(\"test_table\")\n" +
+                "            .build();\n" +
+                "    }\n" +
+                "\n" +
+                "    /**\n" +
+                "     * {@inheritDoc}\n" +
+                "     */\n" +
+                "    @Override\n" +
+                "    @NonNull\n" +
+                "    protected UpdateQuery mapToUpdateQuery(@NonNull TestItem object) {\n" +
+                "        return UpdateQuery.builder()\n" +
+                "            .table(\"test_table\")\n" +
+                "            .where(\"column1 = ?\")\n" +
+                "            .whereArgs(object.column1Field)\n" +
+                "            .build();\n" +
+                "    }\n" +
+                "\n" +
+                "    /**\n" +
+                "     * {@inheritDoc}\n" +
+                "     */\n" +
+                "    @Override\n" +
+                "    @NonNull\n" +
+                "    public ContentValues mapToContentValues(@NonNull TestItem object) {\n" +
+                "        ContentValues contentValues = new ContentValues(2);\n" +
+                "\n" +
+                "        contentValues.put(\"column1\", object.column1Field);\n" +
+                "        contentValues.put(\"column2\", object.column2Field);\n" +
+                "\n" +
+                "        return contentValues;\n" +
+                "    }\n" +
+                "}\n", out.toString());
+    }
+}
diff --git a/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/QueryGeneratorTest.java b/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/QueryGeneratorTest.java
new file mode 100644
index 0000000..81dc375
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/generate/QueryGeneratorTest.java
@@ -0,0 +1,91 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor.generate;
+
+import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteColumn;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteColumnMeta;
+import com.pushtorefresh.storio.sqlite.annotations.processor.introspection.StorIOSQLiteTypeMeta;
+
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class QueryGeneratorTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void createWhereNullStorIOSQLiteTypeMeta() {
+        QueryGenerator.createWhere(null, "object");
+    }
+
+    @Test
+    public void createWhereNoColumns() {
+        final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = new StorIOSQLiteTypeMeta(null, null, null);
+        assertEquals(Collections.emptyMap(), QueryGenerator.createWhere(storIOSQLiteTypeMeta, "object"));
+    }
+
+    @Test
+    public void createWhereNoKeyColumns() {
+        final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = new StorIOSQLiteTypeMeta(null, null, null);
+
+        final StorIOSQLiteColumn storIOSQLiteColumn1 = mock(StorIOSQLiteColumn.class);
+        when(storIOSQLiteColumn1.key()).thenReturn(false);
+        storIOSQLiteTypeMeta.columns.put("column1", new StorIOSQLiteColumnMeta(null, null, null, null, storIOSQLiteColumn1));
+
+        final StorIOSQLiteColumn storIOSQLiteColumn2 = mock(StorIOSQLiteColumn.class);
+        when(storIOSQLiteColumn2.key()).thenReturn(false);
+        storIOSQLiteTypeMeta.columns.put("column2", new StorIOSQLiteColumnMeta(null, null, null, null, storIOSQLiteColumn2));
+
+        assertEquals(Collections.emptyMap(), QueryGenerator.createWhere(storIOSQLiteTypeMeta, "object"));
+    }
+
+    @Test
+    public void createWhereOneKeyColumn() {
+        final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = new StorIOSQLiteTypeMeta(null, null, null);
+
+        final StorIOSQLiteColumn storIOSQLiteColumn1 = mock(StorIOSQLiteColumn.class);
+        when(storIOSQLiteColumn1.key()).thenReturn(false);
+        storIOSQLiteTypeMeta.columns.put("column1", new StorIOSQLiteColumnMeta(null, null, null, null, storIOSQLiteColumn1));
+
+        final StorIOSQLiteColumn storIOSQLiteColumn2 = mock(StorIOSQLiteColumn.class);
+        when(storIOSQLiteColumn2.key()).thenReturn(true);
+        when(storIOSQLiteColumn2.name()).thenReturn("column2");
+        storIOSQLiteTypeMeta.columns.put("column2", new StorIOSQLiteColumnMeta(null, null, "testField1", null, storIOSQLiteColumn2));
+
+        final StorIOSQLiteColumn storIOSQLiteColumn3 = mock(StorIOSQLiteColumn.class);
+        when(storIOSQLiteColumn3.key()).thenReturn(false);
+        storIOSQLiteTypeMeta.columns.put("column3", new StorIOSQLiteColumnMeta(null, null, null, null, storIOSQLiteColumn3));
+
+        final Map<String, String> where = QueryGenerator.createWhere(storIOSQLiteTypeMeta, "object");
+
+        assertEquals("column2 = ?", where.get(QueryGenerator.WHERE_CLAUSE));
+        assertEquals("object.testField1", where.get(QueryGenerator.WHERE_ARGS));
+    }
+
+    @Test
+    public void createWhereMultipleKeyColumns() {
+        final StorIOSQLiteTypeMeta storIOSQLiteTypeMeta = new StorIOSQLiteTypeMeta(null, null, null);
+
+        final StorIOSQLiteColumn storIOSQLiteColumn1 = mock(StorIOSQLiteColumn.class);
+        when(storIOSQLiteColumn1.key()).thenReturn(true);
+        when(storIOSQLiteColumn1.name()).thenReturn("column1");
+        storIOSQLiteTypeMeta.columns.put("column1", new StorIOSQLiteColumnMeta(null, null, "testField1", null, storIOSQLiteColumn1));
+
+        final StorIOSQLiteColumn storIOSQLiteColumn2 = mock(StorIOSQLiteColumn.class);
+        when(storIOSQLiteColumn2.key()).thenReturn(false);
+        storIOSQLiteTypeMeta.columns.put("column2", new StorIOSQLiteColumnMeta(null, null, null, null, storIOSQLiteColumn2));
+
+        final StorIOSQLiteColumn storIOSQLiteColumn3 = mock(StorIOSQLiteColumn.class);
+        when(storIOSQLiteColumn3.key()).thenReturn(true);
+        when(storIOSQLiteColumn3.name()).thenReturn("column3");
+        storIOSQLiteTypeMeta.columns.put("column3", new StorIOSQLiteColumnMeta(null, null, "testField3", null, storIOSQLiteColumn3));
+
+        final Map<String, String> where = QueryGenerator.createWhere(storIOSQLiteTypeMeta, "object");
+
+        assertEquals("column1 = ? AND column3 = ?", where.get(QueryGenerator.WHERE_CLAUSE));
+        assertEquals("object.testField1, object.testField3", where.get(QueryGenerator.WHERE_ARGS));
+    }
+}
diff --git a/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/JavaTypeTest.java b/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/JavaTypeTest.java
new file mode 100644
index 0000000..833455c
--- /dev/null
+++ b/storio-sqlite-annotations-processor/src/test/java/com/pushtorefresh/storio/sqlite/annotations/processor/introspection/JavaTypeTest.java
@@ -0,0 +1,116 @@
+package com.pushtorefresh.storio.sqlite.annotations.processor.introspection;
+
+import org.junit.Test;
+
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.BOOLEAN;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.BOOLEAN_OBJECT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.DOUBLE;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.DOUBLE_OBJECT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.FLOAT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.FLOAT_OBJECT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.INTEGER;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.INTEGER_OBJECT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.LONG;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.LONG_OBJECT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.SHORT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.SHORT_OBJECT;
+import static com.pushtorefresh.storio.sqlite.annotations.processor.introspection.JavaType.STRING;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class JavaTypeTest {
+
+    private static TypeMirror mockTypeMirror(TypeKind typeKind, String typeName) {
+        final TypeMirror typeMirror = mock(TypeMirror.class);
+
+        when(typeMirror.getKind())
+                .thenReturn(typeKind);
+
+        when(typeMirror.toString())
+                .thenReturn(typeName);
+
+        return typeMirror;
+    }
+
+    @Test
+    public void fromBoolean() {
+        final TypeMirror typeMirror = mockTypeMirror(TypeKind.BOOLEAN, null);
+        assertEquals(BOOLEAN, JavaType.from(typeMirror));
+    }
+
+    @Test
+    public void fromBooleanObject() {
+        final TypeMirror typeMirror = mockTypeMirror(null, "java.lang.Boolean");
+        assertEquals(BOOLEAN_OBJECT, JavaType.from(typeMirror));
+    }
+
+    @Test
+    public void fromShort() {
+        final TypeMirror typeMirror = mockTypeMirror(TypeKind.SHORT, null);
+        assertEquals(SHORT, JavaType.from(typeMirror));
+    }
+
+    @Test
+    public void fromShortObject() {
+        final TypeMirror typeMirror = mockTypeMirror(null, "java.lang.Short");
+        assertEquals(SHORT_OBJECT, JavaType.from(typeMirror));
+    }
+
+    @Test
+    public void fromInteger() {
+        final TypeMirror typeMirror = mockTypeMirror(TypeKind.INT, null);
+        assertEquals(INTEGER, JavaType.from(typeMirror));
+    }
+
+    @Test
+    public void fromIntegerObject() {
+        final TypeMirror typeMirror = mockTypeMirror(null, "java.lang.Integer");
+        assertEquals(INTEGER_OBJECT, JavaType.from(typeMirror));
+    }
+
+    @Test
+    public void fromLong() {
+        final TypeMirror typeMirror = mockTypeMirror(TypeKind.LONG, null);
+        assertEquals(LONG, JavaType.from(typeMirror));
+    }
+
+    @Test
+    public void fromLongObject() {
+        final TypeMirror typeMirror = mockTypeMirror(null, "java.lang.Long");
+        assertEquals(LONG_OBJECT, JavaType.from(typeMirror));
+    }
+
+    @Test
+    public void fromFloat() {
+        final TypeMirror typeMirror = mockTypeMirror(TypeKind.FLOAT, null);
+        assertEquals(FLOAT, JavaType.from(typeMirror));
+    }
+
+    @Test
+    public void fromFloatObject() {
+        final TypeMirror typeMirror = mockTypeMirror(null, "java.lang.Float");
+        assertEquals(FLOAT_OBJECT, JavaType.from(typeMirror));
+    }
+
+    @Test
+    public void fromDouble() {
+        final TypeMirror typeMirror = mockTypeMirror(TypeKind.DOUBLE, null);
+        assertEquals(DOUBLE, JavaType.from(typeMirror));
+    }
+
+    @Test
+    public void fromDoubleObject() {
+        final TypeMirror typeMirror = mockTypeMirror(null, "java.lang.Double");
+        assertEquals(DOUBLE_OBJECT, JavaType.from(typeMirror));
+    }
+
+    @Test
+    public void fromString() {
+        final TypeMirror typeMirror = mockTypeMirror(null, "java.lang.String");
+        assertEquals(STRING, JavaType.from(typeMirror));
+    }
+}
diff --git a/storio-sqlite-annotations/build.gradle b/storio-sqlite-annotations/build.gradle
new file mode 100644
index 0000000..40ef981
--- /dev/null
+++ b/storio-sqlite-annotations/build.gradle
@@ -0,0 +1,6 @@
+apply plugin: 'java'
+
+targetCompatibility = '1.6'
+sourceCompatibility = '1.6'
+
+apply from: '../gradle/publish-java-lib.gradle'
\ No newline at end of file
diff --git a/storio-sqlite-annotations/gradle.properties b/storio-sqlite-annotations/gradle.properties
new file mode 100644
index 0000000..0cba16f
--- /dev/null
+++ b/storio-sqlite-annotations/gradle.properties
@@ -0,0 +1,3 @@
+POM_NAME=sqlite-annotations
+POM_ARTIFACT_ID=sqlite-annotations
+POM_PACKAGING=jar
\ No newline at end of file
diff --git a/storio-sqlite-annotations/src/main/java/com/pushtorefresh/storio/sqlite/annotations/StorIOSQLiteColumn.java b/storio-sqlite-annotations/src/main/java/com/pushtorefresh/storio/sqlite/annotations/StorIOSQLiteColumn.java
new file mode 100644
index 0000000..10f29fe
--- /dev/null
+++ b/storio-sqlite-annotations/src/main/java/com/pushtorefresh/storio/sqlite/annotations/StorIOSQLiteColumn.java
@@ -0,0 +1,29 @@
+package com.pushtorefresh.storio.sqlite.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotation for marking field of some class as SQLite column
+ */
+@Target(FIELD)
+@Retention(RUNTIME) // we allow users to write reflection based code to work with annotation
+public @interface StorIOSQLiteColumn {
+
+    /**
+     * Required: specifies column name
+     *
+     * @return non-null column name
+     */
+    String name();
+
+    /**
+     * Optional: marks column as key, so it will be used to identify rows for Put and Delete Operations
+     *
+     * @return true if column is key, false otherwise
+     */
+    boolean key() default false;
+}
diff --git a/storio-sqlite-annotations/src/main/java/com/pushtorefresh/storio/sqlite/annotations/StorIOSQLiteType.java b/storio-sqlite-annotations/src/main/java/com/pushtorefresh/storio/sqlite/annotations/StorIOSQLiteType.java
new file mode 100644
index 0000000..0050c95
--- /dev/null
+++ b/storio-sqlite-annotations/src/main/java/com/pushtorefresh/storio/sqlite/annotations/StorIOSQLiteType.java
@@ -0,0 +1,22 @@
+package com.pushtorefresh.storio.sqlite.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotation for marking class as StorIOSQLiteType to generate object mapping code
+ */
+@Target(TYPE)
+@Retention(RUNTIME) // we allow users to write reflection based code to work with annotation
+public @interface StorIOSQLiteType {
+
+    /**
+     * Required: Specifies table name
+     *
+     * @return table name
+     */
+    String table();
+}
diff --git a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/BaseTest.java b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/BaseTest.java
index 751025c..87655f9 100644
--- a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/BaseTest.java
+++ b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/BaseTest.java
@@ -7,10 +7,10 @@
 
 import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
 import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.operation.delete.DeleteResult;
-import com.pushtorefresh.storio.sqlite.operation.delete.DeleteResults;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResult;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResults;
+import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResult;
+import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResults;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResult;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResults;
 
 import org.junit.Before;
 
diff --git a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/DeleteTest.java b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/DeleteTest.java
index d562c8e..fdd243c 100644
--- a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/DeleteTest.java
+++ b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/DeleteTest.java
@@ -3,7 +3,7 @@
 import android.database.Cursor;
 import android.support.test.runner.AndroidJUnit4;
 
-import com.pushtorefresh.storio.sqlite.operation.delete.DeleteResults;
+import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResults;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/QueryTest.java b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/QueryTest.java
index c92157e..66bfd1b 100644
--- a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/QueryTest.java
+++ b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/QueryTest.java
@@ -4,10 +4,10 @@
 import android.support.annotation.NonNull;
 import android.support.test.runner.AndroidJUnit4;
 
-import com.pushtorefresh.storio.sqlite.operation.get.DefaultGetResolver;
-import com.pushtorefresh.storio.sqlite.operation.get.GetResolver;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
+import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver;
+import com.pushtorefresh.storio.sqlite.operations.get.GetResolver;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/TweetTableMeta.java b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/TweetTableMeta.java
index cb1296d..0ed19f5 100644
--- a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/TweetTableMeta.java
+++ b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/TweetTableMeta.java
@@ -4,15 +4,15 @@
 import android.database.Cursor;
 import android.support.annotation.NonNull;
 
-import com.pushtorefresh.storio.sqlite.operation.delete.DefaultDeleteResolver;
-import com.pushtorefresh.storio.sqlite.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.sqlite.operation.get.DefaultGetResolver;
-import com.pushtorefresh.storio.sqlite.operation.get.GetResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.DefaultPutResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResolver;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-import com.pushtorefresh.storio.sqlite.query.InsertQuery;
-import com.pushtorefresh.storio.sqlite.query.UpdateQuery;
+import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver;
+import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver;
+import com.pushtorefresh.storio.sqlite.operations.get.GetResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResolver;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+import com.pushtorefresh.storio.sqlite.queries.InsertQuery;
+import com.pushtorefresh.storio.sqlite.queries.UpdateQuery;
 
 public class TweetTableMeta {
 
diff --git a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/UpdateTest.java b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/UpdateTest.java
index 805c861..fabbc3c 100644
--- a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/UpdateTest.java
+++ b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/UpdateTest.java
@@ -3,8 +3,8 @@
 import android.database.Cursor;
 import android.support.test.runner.AndroidJUnit4;
 
-import com.pushtorefresh.storio.sqlite.operation.put.PutResult;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResults;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResult;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResults;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
diff --git a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/UserTableMeta.java b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/UserTableMeta.java
index ccdd362..4613838 100644
--- a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/UserTableMeta.java
+++ b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/UserTableMeta.java
@@ -5,17 +5,17 @@
 import android.support.annotation.NonNull;
 
 import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.operation.delete.DefaultDeleteResolver;
-import com.pushtorefresh.storio.sqlite.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.sqlite.operation.get.DefaultGetResolver;
-import com.pushtorefresh.storio.sqlite.operation.get.GetResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.DefaultPutResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResult;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-import com.pushtorefresh.storio.sqlite.query.InsertQuery;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.UpdateQuery;
+import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver;
+import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver;
+import com.pushtorefresh.storio.sqlite.operations.get.GetResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResult;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+import com.pushtorefresh.storio.sqlite.queries.InsertQuery;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.UpdateQuery;
 
 public class UserTableMeta {
 
diff --git a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/auto_parcel/AutoParcelTest.java b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/auto_parcel/AutoParcelTest.java
index 04a803a..f30db48 100644
--- a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/auto_parcel/AutoParcelTest.java
+++ b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/auto_parcel/AutoParcelTest.java
@@ -7,10 +7,10 @@
 import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
 import com.pushtorefresh.storio.sqlite.StorIOSQLite;
 import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite;
-import com.pushtorefresh.storio.sqlite.operation.delete.DeleteResult;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResult;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-import com.pushtorefresh.storio.sqlite.query.Query;
+import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResult;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResult;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+import com.pushtorefresh.storio.sqlite.queries.Query;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/auto_parcel/BookTableMeta.java b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/auto_parcel/BookTableMeta.java
index 08c672a..92ea93d 100644
--- a/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/auto_parcel/BookTableMeta.java
+++ b/storio-sqlite/src/androidTest/java/com/pushtorefresh/storio/sqlite/impl/auto_parcel/BookTableMeta.java
@@ -4,15 +4,15 @@
 import android.database.Cursor;
 import android.support.annotation.NonNull;
 
-import com.pushtorefresh.storio.sqlite.operation.delete.DefaultDeleteResolver;
-import com.pushtorefresh.storio.sqlite.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.sqlite.operation.get.DefaultGetResolver;
-import com.pushtorefresh.storio.sqlite.operation.get.GetResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.DefaultPutResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResolver;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-import com.pushtorefresh.storio.sqlite.query.InsertQuery;
-import com.pushtorefresh.storio.sqlite.query.UpdateQuery;
+import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver;
+import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver;
+import com.pushtorefresh.storio.sqlite.operations.get.GetResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResolver;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+import com.pushtorefresh.storio.sqlite.queries.InsertQuery;
+import com.pushtorefresh.storio.sqlite.queries.UpdateQuery;
 
 final class BookTableMeta {
 
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/SQLiteTypeMapping.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/SQLiteTypeMapping.java
index afcd485..c7d6b4a 100644
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/SQLiteTypeMapping.java
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/SQLiteTypeMapping.java
@@ -2,9 +2,9 @@
 
 import android.support.annotation.NonNull;
 
-import com.pushtorefresh.storio.sqlite.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.sqlite.operation.get.GetResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResolver;
+import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.sqlite.operations.get.GetResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResolver;
 
 import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
 
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/StorIOSQLite.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/StorIOSQLite.java
index c2b1721..56a10b3 100644
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/StorIOSQLite.java
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/StorIOSQLite.java
@@ -6,15 +6,15 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.WorkerThread;
 
-import com.pushtorefresh.storio.sqlite.operation.delete.PreparedDelete;
-import com.pushtorefresh.storio.sqlite.operation.execute.PreparedExecuteSQL;
-import com.pushtorefresh.storio.sqlite.operation.get.PreparedGet;
-import com.pushtorefresh.storio.sqlite.operation.put.PreparedPut;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-import com.pushtorefresh.storio.sqlite.query.InsertQuery;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
-import com.pushtorefresh.storio.sqlite.query.UpdateQuery;
+import com.pushtorefresh.storio.sqlite.operations.delete.PreparedDelete;
+import com.pushtorefresh.storio.sqlite.operations.execute.PreparedExecuteSQL;
+import com.pushtorefresh.storio.sqlite.operations.get.PreparedGet;
+import com.pushtorefresh.storio.sqlite.operations.put.PreparedPut;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+import com.pushtorefresh.storio.sqlite.queries.InsertQuery;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
+import com.pushtorefresh.storio.sqlite.queries.UpdateQuery;
 
 import java.io.Closeable;
 import java.util.Collections;
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/impl/DefaultStorIOSQLite.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/impl/DefaultStorIOSQLite.java
index 5bf7387..118be00 100644
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/impl/DefaultStorIOSQLite.java
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/impl/DefaultStorIOSQLite.java
@@ -11,11 +11,11 @@
 import com.pushtorefresh.storio.sqlite.Changes;
 import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
 import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-import com.pushtorefresh.storio.sqlite.query.InsertQuery;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
-import com.pushtorefresh.storio.sqlite.query.UpdateQuery;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+import com.pushtorefresh.storio.sqlite.queries.InsertQuery;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
+import com.pushtorefresh.storio.sqlite.queries.UpdateQuery;
 
 import java.io.IOException;
 import java.util.HashMap;
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DefaultDeleteResolver.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DefaultDeleteResolver.java
deleted file mode 100644
index f511aa8..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DefaultDeleteResolver.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-
-/**
- * Default implementation of {@link DeleteResolver}.
- * Thread-safe.
- */
-public abstract class DefaultDeleteResolver<T> extends DeleteResolver<T> {
-
-    /**
-     * Converts object to {@link DeleteQuery}.
-     *
-     * @param object object that should be deleted.
-     * @return {@link DeleteQuery} that will be performed.
-     */
-    @NonNull
-    protected abstract DeleteQuery mapToDeleteQuery(@NonNull T object);
-
-    /**
-     * {@inheritDoc}
-     */
-    @NonNull
-    @Override
-    public DeleteResult performDelete(@NonNull StorIOSQLite storIOSQLite, @NonNull T object) {
-        final DeleteQuery deleteQuery = mapToDeleteQuery(object);
-        final int numberOfRowsDeleted = storIOSQLite.internal().delete(deleteQuery);
-        return DeleteResult.newInstance(numberOfRowsDeleted, deleteQuery.table());
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResolver.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResolver.java
deleted file mode 100644
index 3f2b80b..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResolver.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-
-/**
- * Defines behavior of Delete Operation.
- * <p>
- * Implementation should be thread-safe!
- */
-public abstract class DeleteResolver<T> {
-
-    /**
-     * Performs delete of an object.
-     *
-     * @param storIOSQLite {@link StorIOSQLite} instance to perform delete on.
-     * @param object       object that should be deleted.
-     * @return non-null result of Delete Operation.
-     */
-    @NonNull
-    public abstract DeleteResult performDelete(@NonNull StorIOSQLite storIOSQLite, @NonNull T object);
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResult.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResult.java
deleted file mode 100644
index 1adb553..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResult.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import android.support.annotation.NonNull;
-
-import java.util.Collections;
-import java.util.Set;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-
-/**
- * Immutable container for result of Delete Operation.
- * <p>
- * Instances of this class are Immutable.
- */
-public final class DeleteResult {
-
-    private final int numberOfRowsDeleted;
-
-    @NonNull
-    private final Set<String> affectedTables;
-
-    private DeleteResult(int numberOfRowsDeleted, @NonNull Set<String> affectedTables) {
-        checkNotNull(affectedTables, "Please specify affected tables");
-        this.numberOfRowsDeleted = numberOfRowsDeleted;
-        this.affectedTables = Collections.unmodifiableSet(affectedTables);
-    }
-
-    /**
-     * Creates new instance of immutable container for results of Delete Operation.
-     *
-     * @param numberOfRowsDeleted number of rows that were deleted.
-     * @param affectedTables      tables that were affected.
-     * @return new instance of immutable container for result of Delete Operation.
-     */
-    @NonNull
-    public static DeleteResult newInstance(int numberOfRowsDeleted, @NonNull Set<String> affectedTables) {
-        checkNotNull(affectedTables, "Please specify affected tables");
-        return new DeleteResult(numberOfRowsDeleted, affectedTables);
-    }
-
-    /**
-     * Creates new instance of immutable container for results of Delete Operation.
-     *
-     * @param numberOfRowsDeleted number of rows that were deleted.
-     * @param affectedTable       table that was affected.
-     * @return new instance of immutable container for results of Delete Operation.
-     */
-    @NonNull
-    public static DeleteResult newInstance(int numberOfRowsDeleted, @NonNull String affectedTable) {
-        checkNotNull(affectedTable, "Please specify affected table");
-        return new DeleteResult(numberOfRowsDeleted, Collections.singleton(affectedTable));
-    }
-
-    /**
-     * Gets number of rows that were deleted.
-     *
-     * @return number of rows that were deleted.
-     */
-    public int numberOfRowsDeleted() {
-        return numberOfRowsDeleted;
-    }
-
-    /**
-     * Gets names of the tables that wer affected by Delete Operation.
-     *
-     * @return unmodifiable set of tables that were affected.
-     */
-    @NonNull
-    public Set<String> affectedTables() {
-        return affectedTables;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        DeleteResult that = (DeleteResult) o;
-
-        if (numberOfRowsDeleted != that.numberOfRowsDeleted) return false;
-        return affectedTables.equals(that.affectedTables);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = numberOfRowsDeleted;
-        result = 31 * result + affectedTables.hashCode();
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "DeleteResult{" +
-                "numberOfRowsDeleted=" + numberOfRowsDeleted +
-                ", affectedTables=" + affectedTables +
-                '}';
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResults.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResults.java
deleted file mode 100644
index 1c07631..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResults.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import android.support.annotation.NonNull;
-
-import java.util.Collections;
-import java.util.Map;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-
-/**
- * Immutable container for results of Delete Operation
- * <p/>
- * Instances of this class are Immutable
- *
- * @param <T> type of objects
- */
-public class DeleteResults<T> {
-
-    @NonNull
-    private final Map<T, DeleteResult> results;
-
-    private DeleteResults(@NonNull Map<T, DeleteResult> results) {
-        checkNotNull(results, "Please specify Delete Operation results");
-        this.results = Collections.unmodifiableMap(results);
-    }
-
-    /**
-     * Creates new instance of immutable container for results of Delete Operation
-     *
-     * @param results map with results of Delete Operation
-     * @param <T>     type of objects
-     * @return new instance of {@link DeleteResults}
-     */
-    @NonNull
-    public static <T> DeleteResults<T> newInstance(@NonNull Map<T, DeleteResult> results) {
-        return new DeleteResults<T>(results);
-    }
-
-    /**
-     * Returns immutable Map of pairs (object, deleteResult)
-     *
-     * @return immutable Map of pairs (object, deleteResult)
-     */
-    @NonNull
-    public Map<T, DeleteResult> results() {
-        return results;
-    }
-
-    /**
-     * Checks whether particular object was deleted
-     *
-     * @param object object to check
-     * @return true if object was deleted, false otherwise
-     */
-    public boolean wasDeleted(@NonNull T object) {
-        return results.containsKey(object);
-    }
-
-    /**
-     * Checks whether particular object was NOT deleted
-     *
-     * @param object object to check
-     * @return true if object was NOT deleter, false if it was deleted
-     */
-    public boolean wasNotDeleted(@NonNull T object) {
-        return !results.containsKey(object);
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        DeleteResults<?> that = (DeleteResults<?>) o;
-
-        return results.equals(that.results);
-    }
-
-    @Override
-    public int hashCode() {
-        return results.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        return "DeleteResults{" +
-                "results=" + results +
-                '}';
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDelete.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDelete.java
deleted file mode 100644
index 6658be9..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDelete.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.operation.PreparedOperation;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-
-import java.util.Collection;
-
-/**
- * Prepared Delete Operation for {@link StorIOSQLite}.
- *
- * @param <T> type of object to delete.
- */
-public abstract class PreparedDelete<T> implements PreparedOperation<T> {
-
-    @NonNull
-    protected final StorIOSQLite storIOSQLite;
-
-    PreparedDelete(@NonNull StorIOSQLite storIOSQLite) {
-        this.storIOSQLite = storIOSQLite;
-    }
-
-    /**
-     * Builder for {@link PreparedDelete}.
-     */
-    public static final class Builder {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        public Builder(@NonNull StorIOSQLite storIOSQLite) {
-            this.storIOSQLite = storIOSQLite;
-        }
-
-        /**
-         * Prepares Delete Operation by {@link com.pushtorefresh.storio.sqlite.query.DeleteQuery}.
-         *
-         * @param deleteQuery query that specifies which rows should be deleted.
-         * @return builder.
-         */
-        @NonNull
-        public PreparedDeleteByQuery.Builder byQuery(@NonNull DeleteQuery deleteQuery) {
-            return new PreparedDeleteByQuery.Builder(storIOSQLite, deleteQuery);
-        }
-
-        /**
-         * Prepares Delete Operation which should delete one object.
-         *
-         * @param object object to delete.
-         * @param <T>    type of the object.
-         * @return builder.
-         */
-        @NonNull
-        public <T> PreparedDeleteObject.Builder<T> object(@NonNull T object) {
-            return new PreparedDeleteObject.Builder<T>(storIOSQLite, object);
-        }
-
-        /**
-         * Prepares Delete Operation which should delete multiple objects.
-         *
-         * @param objects objects to delete.
-         * @param <T>     type of objects.
-         * @return builder.
-         */
-        @NonNull
-        public <T> PreparedDeleteCollectionOfObjects.Builder<T> objects(@NonNull Collection<T> objects) {
-            return new PreparedDeleteCollectionOfObjects.Builder<T>(storIOSQLite, objects);
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteByQuery.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteByQuery.java
deleted file mode 100644
index ebc4d14..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteByQuery.java
+++ /dev/null
@@ -1,131 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-import com.pushtorefresh.storio.sqlite.Changes;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Delete Operation for {@link StorIOSQLite}.
- */
-public final class PreparedDeleteByQuery extends PreparedDelete<DeleteResult> {
-
-    @NonNull
-    private final DeleteQuery deleteQuery;
-
-    @NonNull
-    private final DeleteResolver<DeleteQuery> deleteResolver;
-
-    PreparedDeleteByQuery(@NonNull StorIOSQLite storIOSQLite, @NonNull DeleteQuery deleteQuery, @NonNull DeleteResolver<DeleteQuery> deleteResolver) {
-        super(storIOSQLite);
-        this.deleteQuery = deleteQuery;
-        this.deleteResolver = deleteResolver;
-    }
-
-    /**
-     * Executes Delete Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null result of Delete Operation.
-     */
-    @WorkerThread
-    @NonNull
-    @Override
-    public DeleteResult executeAsBlocking() {
-        final DeleteResult deleteResult = deleteResolver.performDelete(storIOSQLite, deleteQuery);
-        storIOSQLite.internal().notifyAboutChanges(Changes.newInstance(deleteResult.affectedTables()));
-        return deleteResult;
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Delete Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * delete only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Delete Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<DeleteResult> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedDeleteByQuery}.
-     */
-    public static final class Builder {
-
-        private static final DeleteResolver<DeleteQuery> STANDARD_DELETE_RESOLVER = new DefaultDeleteResolver<DeleteQuery>() {
-            @NonNull
-            @Override
-            public DeleteQuery mapToDeleteQuery(@NonNull DeleteQuery deleteQuery) {
-                return deleteQuery; // no transformations
-            }
-        };
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        @NonNull
-        private final DeleteQuery deleteQuery;
-
-        private DeleteResolver<DeleteQuery> deleteResolver;
-
-        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull DeleteQuery deleteQuery) {
-            this.storIOSQLite = storIOSQLite;
-            this.deleteQuery = deleteQuery;
-        }
-
-        /**
-         * Optional: Specifies Delete Resolver for Delete Operation.
-         * <p/>
-         * If no value was specified, builder will use resolver that
-         * simply redirects query to {@link StorIOSQLite}.
-         *
-         * @param deleteResolver nullable resolver for Delete Operation.
-         * @return builder.
-         */
-        @NonNull
-        public Builder withDeleteResolver(@Nullable DeleteResolver<DeleteQuery> deleteResolver) {
-            this.deleteResolver = deleteResolver;
-            return this;
-        }
-
-        /**
-         * Prepares Delete Operation.
-         *
-         * @return {@link PreparedDeleteByQuery} instance.
-         */
-        @NonNull
-        public PreparedDeleteByQuery prepare() {
-            if (deleteResolver == null) {
-                deleteResolver = STANDARD_DELETE_RESOLVER;
-            }
-
-            return new PreparedDeleteByQuery(storIOSQLite, deleteQuery, deleteResolver);
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteCollectionOfObjects.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteCollectionOfObjects.java
deleted file mode 100644
index 005512a..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteCollectionOfObjects.java
+++ /dev/null
@@ -1,244 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-import com.pushtorefresh.storio.sqlite.Changes;
-import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-
-import java.util.AbstractMap.SimpleImmutableEntry;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Delete Operation for {@link StorIOSQLite}.
- *
- * @param <T> type of objects to delete.
- */
-public final class PreparedDeleteCollectionOfObjects<T> extends PreparedDelete<DeleteResults<T>> {
-
-    @NonNull
-    private final Collection<T> objects;
-
-    @Nullable
-    private final DeleteResolver<T> explicitDeleteResolver;
-
-    private final boolean useTransaction;
-
-    PreparedDeleteCollectionOfObjects(@NonNull StorIOSQLite storIOSQLite,
-                                      @NonNull Collection<T> objects,
-                                      @Nullable DeleteResolver<T> explicitDeleteResolver,
-                                      boolean useTransaction) {
-        super(storIOSQLite);
-        this.objects = objects;
-        this.explicitDeleteResolver = explicitDeleteResolver;
-        this.useTransaction = useTransaction;
-    }
-
-    /**
-     * Executes Delete Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null results of Delete Operation.
-     */
-    @SuppressWarnings("unchecked")
-    @WorkerThread
-    @NonNull
-    @Override
-    public DeleteResults<T> executeAsBlocking() {
-        final StorIOSQLite.Internal internal = storIOSQLite.internal();
-
-        // Nullable
-        final List<SimpleImmutableEntry<T, DeleteResolver<T>>> objectsAndDeleteResolvers;
-
-        if (explicitDeleteResolver != null) {
-            objectsAndDeleteResolvers = null;
-        } else {
-            objectsAndDeleteResolvers
-                    = new ArrayList<SimpleImmutableEntry<T, DeleteResolver<T>>>(objects.size());
-
-            for (final T object : objects) {
-                final SQLiteTypeMapping<T> typeMapping
-                        = (SQLiteTypeMapping<T>) internal.typeMapping(object.getClass());
-
-                if (typeMapping == null) {
-                    throw new IllegalStateException("One of the objects from the collection does not have type mapping: " +
-                            "object = " + object + ", object.class = " + object.getClass() + "," +
-                            "db was not affected by this operation, please add type mapping for this type");
-                }
-
-                objectsAndDeleteResolvers.add(new SimpleImmutableEntry<T, DeleteResolver<T>>(
-                        object,
-                        typeMapping.deleteResolver()
-                ));
-            }
-        }
-
-        if (useTransaction) {
-            internal.beginTransaction();
-        }
-
-        final Map<T, DeleteResult> results = new HashMap<T, DeleteResult>(objects.size());
-        boolean transactionSuccessful = false;
-
-        try {
-            if (explicitDeleteResolver != null) {
-                for (final T object : objects) {
-                    final DeleteResult deleteResult = explicitDeleteResolver.performDelete(storIOSQLite, object);
-
-                    results.put(object, deleteResult);
-
-                    if (!useTransaction) {
-                        internal.notifyAboutChanges(Changes.newInstance(deleteResult.affectedTables()));
-                    }
-                }
-            } else {
-                for (final SimpleImmutableEntry<T, DeleteResolver<T>> objectAndDeleteResolver : objectsAndDeleteResolvers) {
-                    final T object = objectAndDeleteResolver.getKey();
-                    final DeleteResolver<T> deleteResolver = objectAndDeleteResolver.getValue();
-
-                    final DeleteResult deleteResult = deleteResolver.performDelete(storIOSQLite, object);
-
-                    results.put(object, deleteResult);
-
-                    if (!useTransaction) {
-                        internal.notifyAboutChanges(Changes.newInstance(deleteResult.affectedTables()));
-                    }
-                }
-            }
-
-            if (useTransaction) {
-                internal.setTransactionSuccessful();
-                transactionSuccessful = true;
-            }
-        } finally {
-            if (useTransaction) {
-                internal.endTransaction();
-
-                // if delete was in transaction and it was successful -> notify about changes
-                if (transactionSuccessful) {
-                    final Set<String> affectedTables = new HashSet<String>(1); // in most cases it will be one table
-
-                    for (final T object : results.keySet()) {
-                        affectedTables.addAll(results.get(object).affectedTables());
-                    }
-
-                    // IMPORTANT: Notifying about change should be done after end of transaction
-                    // It'll reduce number of possible deadlock situations
-                    internal.notifyAboutChanges(Changes.newInstance(affectedTables));
-                }
-            }
-        }
-
-        return DeleteResults.newInstance(results);
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Delete Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * delete only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Delete Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<DeleteResults<T>> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedDeleteCollectionOfObjects}.
-     *
-     * @param <T> type of objects to delete.
-     */
-    public static final class Builder<T> {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        @NonNull
-        private final Collection<T> objects;
-
-        private DeleteResolver<T> deleteResolver;
-
-        private boolean useTransaction = true;
-
-        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull Collection<T> objects) {
-            this.storIOSQLite = storIOSQLite;
-            this.objects = objects;
-        }
-
-        /**
-         * Optional: Defines that Delete Operation will use transaction or not.
-         * <p/>
-         * By default, transaction will be used.
-         *
-         * @param useTransaction {@code true} to use transaction, {@code false} to not.
-         * @return builder.
-         */
-        @NonNull
-        public Builder<T> useTransaction(boolean useTransaction) {
-            this.useTransaction = useTransaction;
-            return this;
-        }
-
-        /**
-         * Optional: Specifies {@link DeleteResolver} for Delete Operation.
-         * <p/>
-         * <p/>
-         * Can be set via {@link SQLiteTypeMapping},
-         * If value is not set via {@link SQLiteTypeMapping}
-         * or explicitly -> exception will be thrown.
-         *
-         * @param deleteResolver {@link DeleteResolver} for Delete Operation.
-         * @return builder.
-         */
-        @NonNull
-        public Builder<T> withDeleteResolver(@Nullable DeleteResolver<T> deleteResolver) {
-            this.deleteResolver = deleteResolver;
-            return this;
-        }
-
-        /**
-         * Prepares Delete Operation.
-         *
-         * @return {@link PreparedDeleteCollectionOfObjects}.
-         */
-        @NonNull
-        public PreparedDeleteCollectionOfObjects<T> prepare() {
-            return new PreparedDeleteCollectionOfObjects<T>(
-                    storIOSQLite,
-                    objects,
-                    deleteResolver,
-                    useTransaction
-            );
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteObject.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteObject.java
deleted file mode 100644
index d857f22..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteObject.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-import com.pushtorefresh.storio.sqlite.Changes;
-import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Delete Operation for {@link StorIOSQLite}.
- *
- * @param <T> type of object to delete.
- */
-public final class PreparedDeleteObject<T> extends PreparedDelete<DeleteResult> {
-
-    @NonNull
-    private final T object;
-
-    @Nullable
-    private final DeleteResolver<T> explicitDeleteResolver;
-
-    PreparedDeleteObject(@NonNull StorIOSQLite storIOSQLite,
-                         @NonNull T object,
-                         @Nullable DeleteResolver<T> explicitDeleteResolver) {
-        super(storIOSQLite);
-        this.object = object;
-        this.explicitDeleteResolver = explicitDeleteResolver;
-    }
-
-    /**
-     * Executes Delete Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null result of Delete Operation.
-     */
-    @SuppressWarnings("unchecked")
-    @WorkerThread
-    @NonNull
-    @Override
-    public DeleteResult executeAsBlocking() {
-        final StorIOSQLite.Internal internal = storIOSQLite.internal();
-
-        final DeleteResolver<T> deleteResolver;
-
-        if (explicitDeleteResolver != null) {
-            deleteResolver = explicitDeleteResolver;
-        } else {
-            final SQLiteTypeMapping<T> typeMapping
-                    = internal.typeMapping((Class<T>) object.getClass());
-
-            if (typeMapping == null) {
-                throw new IllegalStateException("Object does not have type mapping: " +
-                        "object = " + object + ", object.class = " + object.getClass() + "," +
-                        "db was not affected by this operation, please add type mapping for this type");
-            }
-
-            deleteResolver = typeMapping.deleteResolver();
-        }
-
-        final DeleteResult deleteResult = deleteResolver.performDelete(storIOSQLite, object);
-        internal.notifyAboutChanges(Changes.newInstance(deleteResult.affectedTables()));
-        return deleteResult;
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Delete Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * delete only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Delete Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<DeleteResult> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedDeleteObject}.
-     *
-     * @param <T> type of object to delete.
-     */
-    public static final class Builder<T> {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        @NonNull
-        private final T object;
-
-        private DeleteResolver<T> deleteResolver;
-
-        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull T object) {
-            this.storIOSQLite = storIOSQLite;
-            this.object = object;
-        }
-
-        /**
-         * Optional: Specifies {@link DeleteResolver} for Delete Operation.
-         * <p/>
-         * Can be set via {@link SQLiteTypeMapping},
-         * If resolver is not set via {@link SQLiteTypeMapping}
-         * or explicitly -> exception will be thrown.
-         *
-         * @param deleteResolver delete resolver.
-         * @return builder.
-         */
-        @NonNull
-        public Builder<T> withDeleteResolver(@NonNull DeleteResolver<T> deleteResolver) {
-            this.deleteResolver = deleteResolver;
-            return this;
-        }
-
-        /**
-         * Prepares Delete Operation.
-         *
-         * @return {@link PreparedDeleteObject} instance.
-         */
-        @NonNull
-        public PreparedDeleteObject<T> prepare() {
-            return new PreparedDeleteObject<T>(
-                    storIOSQLite,
-                    object,
-                    deleteResolver
-            );
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/execute/PreparedExecuteSQL.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/execute/PreparedExecuteSQL.java
deleted file mode 100644
index 5f76646..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/execute/PreparedExecuteSQL.java
+++ /dev/null
@@ -1,146 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.execute;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.operation.PreparedOperation;
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-import com.pushtorefresh.storio.sqlite.Changes;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
-
-import java.util.Set;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Execute SQL Operation for {@link StorIOSQLite}.
- */
-public final class PreparedExecuteSQL implements PreparedOperation<Object> {
-
-    @NonNull
-    private final StorIOSQLite storIOSQLite;
-
-    @NonNull
-    private final RawQuery rawQuery;
-
-    PreparedExecuteSQL(@NonNull StorIOSQLite storIOSQLite, @NonNull RawQuery rawQuery) {
-        this.storIOSQLite = storIOSQLite;
-        this.rawQuery = rawQuery;
-    }
-
-    /**
-     * Executes SQL Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return just a new instance of {@link Object}, actually Execute SQL should return {@code void},
-     * but we can not return instance of {@link Void} so we just return {@link Object}
-     * and you don't have to deal with {@code null}.
-     */
-    @WorkerThread
-    @NonNull
-    @Override
-    public Object executeAsBlocking() {
-        storIOSQLite.internal().executeSQL(rawQuery);
-
-        final Set<String> affectedTables = rawQuery.affectsTables();
-
-        if (affectedTables.size() > 0) {
-            storIOSQLite.internal().notifyAboutChanges(Changes.newInstance(affectedTables));
-        }
-
-        return new Object();
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Execute SQL Operation
-     * and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * execution of SQL only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Delete Operation
-     * and send result to observer. Result: just a new instance of {@link Object},
-     * actually Execute SQL should return {@code void},
-     * but we can not return instance of {@link Void} so we just return {@link Object}
-     * and you don't have to deal with {@code null}.
-     */
-    @NonNull
-    @Override
-    public Observable<Object> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedExecuteSQL}.
-     */
-    public static final class Builder {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        public Builder(@NonNull StorIOSQLite storIOSQLite) {
-            this.storIOSQLite = storIOSQLite;
-        }
-
-        /**
-         * Required: Specifies query for ExecSql Operation.
-         *
-         * @param rawQuery any SQL query that you want to execute, but please, be careful with it.
-         *                 Don't forget that you can set affected tables to the {@link RawQuery},
-         *                 so ExecSQL operation will send notification about changes in that tables.
-         * @return builder.
-         */
-        @NonNull
-        public CompleteBuilder withQuery(@NonNull RawQuery rawQuery) {
-            checkNotNull(rawQuery, "Please set query object");
-            return new CompleteBuilder(storIOSQLite, rawQuery);
-        }
-    }
-
-    /**
-     * Compile-time safe part of {@link Builder}.
-     */
-    public static final class CompleteBuilder {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        @NonNull
-        private final RawQuery rawQuery;
-
-        CompleteBuilder(@NonNull StorIOSQLite storIOSQLite, @NonNull RawQuery rawQuery) {
-            this.storIOSQLite = storIOSQLite;
-            this.rawQuery = rawQuery;
-        }
-
-        /**
-         * Prepares ExecSql Operation.
-         *
-         * @return {@link PreparedExecuteSQL} instance.
-         */
-        @NonNull
-        public PreparedExecuteSQL prepare() {
-            return new PreparedExecuteSQL(
-                    storIOSQLite,
-                    rawQuery
-            );
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/DefaultGetResolver.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/DefaultGetResolver.java
deleted file mode 100644
index 4c50a6d..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/DefaultGetResolver.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.get;
-
-import android.database.Cursor;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
-
-/**
- * Default implementation of {@link GetResolver}.
- * <p>
- * Thread-safe.
- * <p>
- * You need to just override mapping from Cursor.
- */
-public abstract class DefaultGetResolver<T> extends GetResolver<T> {
-
-    /**
-     * {@inheritDoc}
-     */
-    @NonNull
-    @Override
-    public Cursor performGet(@NonNull StorIOSQLite storIOSQLite, @NonNull RawQuery rawQuery) {
-        return storIOSQLite.internal().rawQuery(rawQuery);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @NonNull
-    @Override
-    public Cursor performGet(@NonNull StorIOSQLite storIOSQLite, @NonNull Query query) {
-        return storIOSQLite.internal().query(query);
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/GetResolver.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/GetResolver.java
deleted file mode 100644
index b6ede76..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/GetResolver.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.get;
-
-import android.database.Cursor;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
-
-/**
- * Defines behavior of Get Operation.
- * <p>
- * Implementation should be thread-safe!
- */
-public abstract class GetResolver<T> {
-
-    /**
-     * Converts {@link Cursor} with already set position to object of required type.
-     *
-     * @param cursor not closed {@link Cursor} with already set position
-     *               that should be parsed and converted to object of required type.
-     * @return non-null object of required type with data parsed from passed {@link Cursor}.
-     */
-    @NonNull
-    public abstract T mapFromCursor(@NonNull Cursor cursor);
-
-    /**
-     * Performs get of results with passed query.
-     *
-     * @param storIOSQLite {@link StorIOSQLite} instance to perform get from.
-     * @param rawQuery     query that should be performed.
-     * @return non-null, not closed {@link Cursor} that can be empty
-     * or contain data with results of Get Operation.
-     */
-    @NonNull
-    public abstract Cursor performGet(@NonNull StorIOSQLite storIOSQLite, @NonNull RawQuery rawQuery);
-
-    /**
-     * Performs get of results with passed query.
-     *
-     * @param storIOSQLite {@link StorIOSQLite} instance to perform get from.
-     * @param query        query that should be performed.
-     * @return non-null, not closed {@link Cursor} that can be empty
-     * or contain data with results of Get Operation.
-     */
-    @NonNull
-    public abstract Cursor performGet(@NonNull StorIOSQLite storIOSQLite, @NonNull Query query);
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGet.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGet.java
deleted file mode 100644
index c395f72..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGet.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.get;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import com.pushtorefresh.storio.operation.PreparedOperation;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
-
-/**
- * Prepared Get Operation for {@link StorIOSQLite}.
- *
- * @param <Result> type of result.
- */
-public abstract class PreparedGet<Result> implements PreparedOperation<Result> {
-
-    @NonNull
-    protected final StorIOSQLite storIOSQLite;
-
-    @Nullable
-    protected final Query query;
-
-    @Nullable
-    protected final RawQuery rawQuery;
-
-    PreparedGet(@NonNull StorIOSQLite storIOSQLite, @NonNull Query query) {
-        this.storIOSQLite = storIOSQLite;
-        this.query = query;
-        this.rawQuery = null;
-    }
-
-    PreparedGet(@NonNull StorIOSQLite storIOSQLite, @NonNull RawQuery rawQuery) {
-        this.storIOSQLite = storIOSQLite;
-        this.rawQuery = rawQuery;
-        query = null;
-    }
-
-    /**
-     * Builder for {@link PreparedGet}.
-     */
-    public static final class Builder {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        public Builder(@NonNull StorIOSQLite storIOSQLite) {
-            this.storIOSQLite = storIOSQLite;
-        }
-
-        /**
-         * Returns builder for Get Operation that returns result as {@link android.database.Cursor}.
-         *
-         * @return builder for Get Operation that returns result as {@link android.database.Cursor}.
-         */
-        @NonNull
-        public PreparedGetCursor.Builder cursor() {
-            return new PreparedGetCursor.Builder(storIOSQLite);
-        }
-
-        /**
-         * Returns builder for Get Operation that returns result as {@link java.util.List} of items.
-         *
-         * @param type type of items.
-         * @param <T>  type of items.
-         * @return builder for Get Operation that returns result as {@link java.util.List} of items.
-         */
-        @NonNull
-        public <T> PreparedGetListOfObjects.Builder<T> listOfObjects(@NonNull Class<T> type) {
-            return new PreparedGetListOfObjects.Builder<T>(storIOSQLite, type);
-        }
-    }
-
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetCursor.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetCursor.java
deleted file mode 100644
index e664e61..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetCursor.java
+++ /dev/null
@@ -1,224 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.get;
-
-import android.database.Cursor;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.operation.internal.MapSomethingToExecuteAsBlocking;
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Get Operation for {@link StorIOSQLite}.
- */
-public final class PreparedGetCursor extends PreparedGet<Cursor> {
-
-    @NonNull
-    private final GetResolver<Cursor> getResolver;
-
-    PreparedGetCursor(@NonNull StorIOSQLite storIOSQLite,
-                      @NonNull Query query,
-                      @NonNull GetResolver<Cursor> getResolver) {
-        super(storIOSQLite, query);
-        this.getResolver = getResolver;
-    }
-
-    PreparedGetCursor(@NonNull StorIOSQLite storIOSQLite,
-                      @NonNull RawQuery rawQuery,
-                      @NonNull GetResolver<Cursor> getResolver) {
-        super(storIOSQLite, rawQuery);
-        this.getResolver = getResolver;
-    }
-
-    /**
-     * Executes Get Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null {@link Cursor}, can be empty.
-     */
-    @WorkerThread
-    @NonNull
-    public Cursor executeAsBlocking() {
-        if (query != null) {
-            return getResolver.performGet(storIOSQLite, query);
-        } else if (rawQuery != null) {
-            return getResolver.performGet(storIOSQLite, rawQuery);
-        } else {
-            throw new IllegalStateException("Please specify query");
-        }
-    }
-
-    /**
-     * Creates "Hot" {@link Observable} which will be subscribed to changes of tables from query
-     * and will emit result each time change occurs.
-     * <p/>
-     * First result will be emitted immediately after subscription,
-     * other emissions will occur only if changes of tables from query will occur during lifetime of
-     * the {@link Observable}.
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     * <p/>
-     * Please don't forget to unsubscribe from this {@link Observable} because
-     * it's "Hot" and endless.
-     *
-     * @return non-null {@link Observable} which will emit non-null
-     * list with mapped results and will be subscribed to changes of tables from query.
-     */
-    @NonNull
-    @Override
-    public Observable<Cursor> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        final Set<String> tables;
-
-        if (query != null) {
-            tables = new HashSet<String>(1);
-            tables.add(query.table());
-        } else if (rawQuery != null) {
-            tables = rawQuery.observesTables();
-        } else {
-            throw new IllegalStateException("Please specify query");
-        }
-
-        if (!tables.isEmpty()) {
-            return storIOSQLite
-                    .observeChangesInTables(tables) // each change triggers executeAsBlocking
-                    .map(MapSomethingToExecuteAsBlocking.newInstance(this))
-                    .startWith(Observable.create(OnSubscribeExecuteAsBlocking.newInstance(this))) // start stream with first query result
-                    .subscribeOn(Schedulers.io());
-        } else {
-            return Observable
-                    .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                    .subscribeOn(Schedulers.io());
-        }
-    }
-
-    /**
-     * Builder for {@link PreparedGetCursor}.
-     * <p/>
-     * Required: You should specify query by call
-     * {@link #withQuery(Query)} or {@link #withQuery(RawQuery)}.
-     */
-    public static final class Builder {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        Builder(@NonNull StorIOSQLite storIOSQLite) {
-            this.storIOSQLite = storIOSQLite;
-        }
-
-        /**
-         * Required: Specifies {@link Query} for Get Operation.
-         *
-         * @param query query.
-         * @return builder.
-         * @see Query
-         */
-        @NonNull
-        public CompleteBuilder withQuery(@NonNull Query query) {
-            checkNotNull(query, "Please specify query");
-            return new CompleteBuilder(storIOSQLite, query);
-        }
-
-        /**
-         * Required: Specifies {@link RawQuery} for Get Operation,
-         * you can use it for "joins" and same constructions which are not allowed for {@link Query}.
-         *
-         * @param rawQuery query.
-         * @return builder.
-         * @see RawQuery
-         */
-        @NonNull
-        public CompleteBuilder withQuery(@NonNull RawQuery rawQuery) {
-            checkNotNull(rawQuery, "Please specify rawQuery");
-            return new CompleteBuilder(storIOSQLite, rawQuery);
-        }
-    }
-
-    /**
-     * Compile-time safe part of builder for {@link PreparedGetCursor}.
-     */
-    public static final class CompleteBuilder {
-
-        private static final GetResolver<Cursor> STANDARD_GET_RESOLVER = new DefaultGetResolver<Cursor>() {
-            @NonNull
-            @Override
-            public Cursor mapFromCursor(@NonNull Cursor cursor) {
-                return cursor; // no modifications
-            }
-        };
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        private final Query query;
-
-        private final RawQuery rawQuery;
-
-        private GetResolver<Cursor> getResolver;
-
-        CompleteBuilder(@NonNull StorIOSQLite storIOSQLite, @NonNull Query query) {
-            this.storIOSQLite = storIOSQLite;
-            this.query = query;
-            this.rawQuery = null;
-        }
-
-        CompleteBuilder(@NonNull StorIOSQLite storIOSQLite, @NonNull RawQuery rawQuery) {
-            this.storIOSQLite = storIOSQLite;
-            this.rawQuery = rawQuery;
-            this.query = null;
-        }
-
-        /**
-         * Optional: Specifies Get Resolver for operation.
-         * If no value is set, builder will use resolver that
-         * simply redirects query to {@link StorIOSQLite}.
-         *
-         * @param getResolver nullable GetResolver for Get Operation.
-         * @return builder.
-         */
-        @NonNull
-        public CompleteBuilder withGetResolver(@Nullable GetResolver<Cursor> getResolver) {
-            this.getResolver = getResolver;
-            return this;
-        }
-
-        /**
-         * Prepares Get Operation.
-         *
-         * @return {@link PreparedGetCursor} instance.
-         */
-        @NonNull
-        public PreparedGetCursor prepare() {
-            if (getResolver == null) {
-                getResolver = STANDARD_GET_RESOLVER;
-            }
-
-            if (query != null) {
-                return new PreparedGetCursor(storIOSQLite, query, getResolver);
-            } else if (rawQuery != null) {
-                return new PreparedGetCursor(storIOSQLite, rawQuery, getResolver);
-            } else {
-                throw new IllegalStateException("Please specify query");
-            }
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetListOfObjects.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetListOfObjects.java
deleted file mode 100644
index 1ae8676..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetListOfObjects.java
+++ /dev/null
@@ -1,292 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.get;
-
-import android.database.Cursor;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.operation.internal.MapSomethingToExecuteAsBlocking;
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-import static java.util.Collections.EMPTY_LIST;
-import static java.util.Collections.unmodifiableList;
-
-/**
- * Prepared Get Operation for {@link StorIOSQLite}.
- *
- * @param <T> type of results.
- */
-public final class PreparedGetListOfObjects<T> extends PreparedGet<List<T>> {
-
-    @NonNull
-    private final Class<T> type;
-
-    @Nullable
-    private final GetResolver<T> explicitGetResolver;
-
-    PreparedGetListOfObjects(@NonNull StorIOSQLite storIOSQLite,
-                             @NonNull Class<T> type,
-                             @NonNull Query query,
-                             @Nullable GetResolver<T> explicitGetResolver) {
-        super(storIOSQLite, query);
-        this.type = type;
-        this.explicitGetResolver = explicitGetResolver;
-    }
-
-    PreparedGetListOfObjects(@NonNull StorIOSQLite storIOSQLite,
-                             @NonNull Class<T> type,
-                             @NonNull RawQuery rawQuery,
-                             @Nullable GetResolver<T> explicitGetResolver) {
-        super(storIOSQLite, rawQuery);
-        this.type = type;
-        this.explicitGetResolver = explicitGetResolver;
-    }
-
-    /**
-     * Executes Get Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null, immutable {@link List} with mapped results, list can be empty.
-     */
-    @WorkerThread
-    @SuppressWarnings({"TryFinallyCanBeTryWithResources", "unchecked"})
-    // Min SDK :( unchecked for empty list
-    @NonNull
-    @Override
-    public List<T> executeAsBlocking() {
-        final GetResolver<T> getResolver;
-
-        if (explicitGetResolver != null) {
-            getResolver = explicitGetResolver;
-        } else {
-            final SQLiteTypeMapping<T> typeMapping = storIOSQLite.internal().typeMapping(type);
-
-            if (typeMapping == null) {
-                throw new IllegalStateException("This type does not have type mapping: " +
-                        "type = " + type + "," +
-                        "db was not touched by this operation, please add type mapping for this type");
-            }
-
-            getResolver = typeMapping.getResolver();
-        }
-
-        final Cursor cursor;
-
-        if (query != null) {
-            cursor = getResolver.performGet(storIOSQLite, query);
-        } else if (rawQuery != null) {
-            cursor = getResolver.performGet(storIOSQLite, rawQuery);
-        } else {
-            throw new IllegalStateException("Please specify query");
-        }
-
-        try {
-            final int count = cursor.getCount();
-
-            if (count == 0) {
-                return EMPTY_LIST; // it's immutable
-            }
-
-            final List<T> list = new ArrayList<T>(count);
-
-            while (cursor.moveToNext()) {
-                list.add(getResolver.mapFromCursor(cursor));
-            }
-
-            return unmodifiableList(list);
-        } finally {
-            cursor.close();
-        }
-    }
-
-    /**
-     * Creates "Hot" {@link Observable} which will be subscribed to changes of tables from query
-     * and will emit result each time change occurs.
-     * <p/>
-     * First result will be emitted immediately after subscription,
-     * other emissions will occur only if changes of tables from query will occur during lifetime of
-     * the {@link Observable}.
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     * <p/>
-     * Please don't forget to unsubscribe from this {@link Observable} because
-     * it's "Hot" and endless.
-     *
-     * @return non-null {@link Observable} which will emit non-null, immutable
-     * {@link List} with mapped results and will be subscribed to changes of tables from query,
-     * list can be empty.
-     */
-    @NonNull
-    @Override
-    public Observable<List<T>> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        final Set<String> tables;
-
-        if (query != null) {
-            tables = Collections.singleton(query.table());
-        } else if (rawQuery != null) {
-            tables = rawQuery.observesTables();
-        } else {
-            throw new IllegalStateException("Please specify query");
-        }
-
-        if (!tables.isEmpty()) {
-            return storIOSQLite
-                    .observeChangesInTables(tables) // each change triggers executeAsBlocking
-                    .map(MapSomethingToExecuteAsBlocking.newInstance(this))
-                    .startWith(Observable.create(OnSubscribeExecuteAsBlocking.newInstance(this))) // start stream with first query result
-                    .subscribeOn(Schedulers.io());
-        } else {
-            return Observable
-                    .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                    .subscribeOn(Schedulers.io());
-        }
-    }
-
-    /**
-     * Builder for {@link PreparedGetListOfObjects} Operation.
-     *
-     * @param <T> type of objects.
-     */
-    public static final class Builder<T> {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        @NonNull
-        private final Class<T> type;
-
-        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull Class<T> type) {
-            this.storIOSQLite = storIOSQLite;
-            this.type = type;
-        }
-
-        /**
-         * Required: Specifies query which will be passed to {@link StorIOSQLite}
-         * to get list of objects.
-         *
-         * @param query non-null query.
-         * @return builder.
-         * @see Query
-         */
-        @NonNull
-        public CompleteBuilder<T> withQuery(@NonNull Query query) {
-            checkNotNull(query, "Please specify query");
-            return new CompleteBuilder<T>(storIOSQLite, type, query);
-        }
-
-        /**
-         * Required: Specifies {@link RawQuery} for Get Operation,
-         * you can use it for "joins" and same constructions which are not allowed for {@link Query}.
-         *
-         * @param rawQuery query.
-         * @return builder.
-         * @see RawQuery
-         */
-        @NonNull
-        public CompleteBuilder<T> withQuery(@NonNull RawQuery rawQuery) {
-            checkNotNull(rawQuery, "Please specify rawQuery");
-            return new CompleteBuilder<T>(storIOSQLite, type, rawQuery);
-        }
-    }
-
-    /**
-     * Compile-safe part of {@link Builder}.
-     *
-     * @param <T> type of objects.
-     */
-    public static final class CompleteBuilder<T> {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        @NonNull
-        private final Class<T> type;
-
-        @Nullable
-        private final Query query;
-
-        @Nullable
-        private final RawQuery rawQuery;
-
-        @Nullable
-        private GetResolver<T> getResolver;
-
-        CompleteBuilder(@NonNull StorIOSQLite storIOSQLite, @NonNull Class<T> type, @NonNull Query query) {
-            this.storIOSQLite = storIOSQLite;
-            this.type = type;
-            this.query = query;
-            rawQuery = null;
-        }
-
-        CompleteBuilder(@NonNull StorIOSQLite storIOSQLite, @NonNull Class<T> type, @NonNull RawQuery rawQuery) {
-            this.storIOSQLite = storIOSQLite;
-            this.type = type;
-            this.rawQuery = rawQuery;
-            query = null;
-        }
-
-        /**
-         * Optional: Specifies resolver for Get Operation which can be used
-         * to provide custom behavior of Get Operation.
-         * <p/>
-         * {@link SQLiteTypeMapping} can be used to set default GetResolver.
-         * If GetResolver is not set via {@link SQLiteTypeMapping}
-         * or explicitly -> exception will be thrown.
-         *
-         * @param getResolver nullable resolver for Get Operation.
-         * @return builder.
-         */
-        @NonNull
-        public CompleteBuilder<T> withGetResolver(@Nullable GetResolver<T> getResolver) {
-            this.getResolver = getResolver;
-            return this;
-        }
-
-        /**
-         * Builds new instance of {@link PreparedGetListOfObjects}.
-         *
-         * @return new instance of {@link PreparedGetListOfObjects}.
-         */
-        @NonNull
-        public PreparedGetListOfObjects<T> prepare() {
-            if (query != null) {
-                return new PreparedGetListOfObjects<T>(
-                        storIOSQLite,
-                        type,
-                        query,
-                        getResolver
-                );
-            } else if (rawQuery != null) {
-                return new PreparedGetListOfObjects<T>(
-                        storIOSQLite,
-                        type,
-                        rawQuery,
-                        getResolver
-                );
-            } else {
-                throw new IllegalStateException("Please specify Query or RawQuery");
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/DefaultPutResolver.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/DefaultPutResolver.java
deleted file mode 100644
index 6917fd7..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/DefaultPutResolver.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.InsertQuery;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.UpdateQuery;
-
-import static com.pushtorefresh.storio.internal.Queries.nullableArrayOfStrings;
-import static com.pushtorefresh.storio.internal.Queries.nullableString;
-
-/**
- * Default implementation of {@link PutResolver}.
- * <p>
- * Thread-safe.
- *
- * @param <T> type of objects to put.
- */
-public abstract class DefaultPutResolver<T> extends PutResolver<T> {
-
-    /**
-     * Converts object of required type to {@link InsertQuery}.
-     *
-     * @param object non-null object that should be converted to {@link InsertQuery}.
-     * @return non-null {@link InsertQuery}.
-     */
-    @NonNull
-    protected abstract InsertQuery mapToInsertQuery(@NonNull T object);
-
-    /**
-     * Converts object of required type to {@link UpdateQuery}.
-     *
-     * @param object non-null object that should be converted to {@link UpdateQuery}.
-     * @return non-null {@link UpdateQuery}.
-     */
-    @NonNull
-    protected abstract UpdateQuery mapToUpdateQuery(@NonNull T object);
-
-    /**
-     * Converts object of required type to {@link ContentValues}.
-     *
-     * @param object non-null object that should be converted to {@link ContentValues}.
-     * @return non-null {@link ContentValues}.
-     */
-    @NonNull
-    protected abstract ContentValues mapToContentValues(@NonNull T object);
-
-    /**
-     * {@inheritDoc}
-     */
-    @NonNull
-    @Override
-    public PutResult performPut(@NonNull StorIOSQLite storIOSQLite, @NonNull T object) {
-        final UpdateQuery updateQuery = mapToUpdateQuery(object);
-
-        // for data consistency in concurrent environment, encapsulate Put Operation into transaction
-        storIOSQLite.internal().beginTransaction();
-
-        try {
-            final Cursor cursor = storIOSQLite.internal().query(Query.builder()
-                    .table(updateQuery.table())
-                    .where(nullableString(updateQuery.where()))
-                    .whereArgs((Object[]) nullableArrayOfStrings(updateQuery.whereArgs()))
-                    .build());
-
-            final PutResult putResult;
-
-            try {
-                final ContentValues contentValues = mapToContentValues(object);
-
-                if (cursor.getCount() == 0) {
-                    final InsertQuery insertQuery = mapToInsertQuery(object);
-                    final long insertedId = storIOSQLite.internal().insert(insertQuery, contentValues);
-                    putResult = PutResult.newInsertResult(insertedId, insertQuery.table());
-                } else {
-                    final int numberOfRowsUpdated = storIOSQLite.internal().update(updateQuery, contentValues);
-                    putResult = PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table());
-                }
-            } finally {
-                cursor.close();
-            }
-
-            // everything okay
-            storIOSQLite.internal().setTransactionSuccessful();
-
-            return putResult;
-        } finally {
-            // in case of bad situations, db won't be affected
-            storIOSQLite.internal().endTransaction();
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPut.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPut.java
deleted file mode 100644
index 71e8b61..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPut.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.content.ContentValues;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.operation.PreparedOperation;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-
-import java.util.Arrays;
-import java.util.Collection;
-
-/**
- * Prepared Put Operation for {@link StorIOSQLite} which performs insert or update data
- * in {@link StorIOSQLite}.
- */
-public abstract class PreparedPut<Result> implements PreparedOperation<Result> {
-
-    @NonNull
-    protected final StorIOSQLite storIOSQLite;
-
-    PreparedPut(@NonNull StorIOSQLite storIOSQLite) {
-        this.storIOSQLite = storIOSQLite;
-    }
-
-    /**
-     * Builder for {@link PreparedPut}.
-     */
-    public static final class Builder {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        public Builder(@NonNull StorIOSQLite storIOSQLite) {
-            this.storIOSQLite = storIOSQLite;
-        }
-
-        /**
-         * Prepares Put Operation for one instance of {@link ContentValues}.
-         *
-         * @param contentValues content values to put.
-         * @return builder.
-         */
-        @NonNull
-        public PreparedPutContentValues.Builder contentValues(@NonNull ContentValues contentValues) {
-            return new PreparedPutContentValues.Builder(storIOSQLite, contentValues);
-        }
-
-        /**
-         * Prepares Put Operation for multiple {@link ContentValues}.
-         *
-         * @param contentValuesIterable content values to put.
-         * @return builder.
-         */
-        @NonNull
-        public PreparedPutContentValuesIterable.Builder contentValues(@NonNull Iterable<ContentValues> contentValuesIterable) {
-            return new PreparedPutContentValuesIterable.Builder(storIOSQLite, contentValuesIterable);
-        }
-
-        /**
-         * Prepares Put Operation for multiple {@link ContentValues}.
-         *
-         * @param contentValuesArray content values to put.
-         * @return builder.
-         */
-        @NonNull
-        public PreparedPutContentValuesIterable.Builder contentValues(@NonNull ContentValues... contentValuesArray) {
-            return new PreparedPutContentValuesIterable.Builder(storIOSQLite, Arrays.asList(contentValuesArray));
-        }
-
-        /**
-         * Prepares Put Operation for one object.
-         *
-         * @param object object to put.
-         * @param <T>    type of object.
-         * @return builder.
-         */
-        @NonNull
-        public <T> PreparedPutObject.Builder<T> object(T object) {
-            return new PreparedPutObject.Builder<T>(storIOSQLite, object);
-        }
-
-        /**
-         * Prepares Put Operation for multiple objects.
-         *
-         * @param objects objects to put.
-         * @param <T>     type of objects.
-         * @return builder.
-         */
-        @NonNull
-        public <T> PreparedPutCollectionOfObjects.Builder<T> objects(@NonNull Collection<T> objects) {
-            return new PreparedPutCollectionOfObjects.Builder<T>(storIOSQLite, objects);
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutCollectionOfObjects.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutCollectionOfObjects.java
deleted file mode 100644
index c841480..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutCollectionOfObjects.java
+++ /dev/null
@@ -1,236 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-import com.pushtorefresh.storio.sqlite.Changes;
-import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-
-import java.util.AbstractMap.SimpleImmutableEntry;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-public final class PreparedPutCollectionOfObjects<T> extends PreparedPut<PutResults<T>> {
-
-    @NonNull
-    private final Collection<T> objects;
-
-    private final boolean useTransaction;
-
-    @Nullable
-    private final PutResolver<T> explicitPutResolver;
-
-    PreparedPutCollectionOfObjects(@NonNull StorIOSQLite storIOSQLite,
-                                   @NonNull Collection<T> objects,
-                                   @Nullable PutResolver<T> explicitPutResolver,
-                                   boolean useTransaction) {
-        super(storIOSQLite);
-        this.objects = objects;
-        this.useTransaction = useTransaction;
-        this.explicitPutResolver = explicitPutResolver;
-    }
-
-    /**
-     * Executes Put Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null results of Put Operation.
-     */
-    @SuppressWarnings("unchecked")
-    @WorkerThread
-    @NonNull
-    @Override
-    public PutResults<T> executeAsBlocking() {
-        final StorIOSQLite.Internal internal = storIOSQLite.internal();
-
-        // Nullable
-        final List<SimpleImmutableEntry<T, PutResolver<T>>> objectsAndPutResolvers;
-
-        if (explicitPutResolver != null) {
-            objectsAndPutResolvers = null;
-        } else {
-            objectsAndPutResolvers = new ArrayList<SimpleImmutableEntry<T, PutResolver<T>>>(objects.size());
-
-            for (final T object : objects) {
-                final SQLiteTypeMapping<T> typeMapping
-                        = (SQLiteTypeMapping<T>) internal.typeMapping(object.getClass());
-
-                if (typeMapping == null) {
-                    throw new IllegalStateException("One of the objects from the collection does not have type mapping: " +
-                            "object = " + object + ", object.class = " + object.getClass() + "," +
-                            "db was not affected by this operation, please add type mapping for this type");
-                }
-
-                objectsAndPutResolvers.add(new SimpleImmutableEntry<T, PutResolver<T>>(
-                        object,
-                        typeMapping.putResolver()
-                ));
-            }
-        }
-
-        if (useTransaction) {
-            internal.beginTransaction();
-        }
-
-        final Map<T, PutResult> results = new HashMap<T, PutResult>(objects.size());
-        boolean transactionSuccessful = false;
-
-        try {
-            if (explicitPutResolver != null) {
-                for (final T object : objects) {
-                    final PutResult putResult = explicitPutResolver.performPut(storIOSQLite, object);
-                    results.put(object, putResult);
-
-                    if (!useTransaction) {
-                        internal.notifyAboutChanges(Changes.newInstance(putResult.affectedTables()));
-                    }
-                }
-            } else {
-                for (final SimpleImmutableEntry<T, PutResolver<T>> objectAndPutResolver : objectsAndPutResolvers) {
-                    final T object = objectAndPutResolver.getKey();
-                    final PutResolver<T> putResolver = objectAndPutResolver.getValue();
-
-                    final PutResult putResult = putResolver.performPut(storIOSQLite, object);
-
-                    results.put(object, putResult);
-
-                    if (!useTransaction) {
-                        internal.notifyAboutChanges(Changes.newInstance(putResult.affectedTables()));
-                    }
-                }
-            }
-
-            if (useTransaction) {
-                internal.setTransactionSuccessful();
-                transactionSuccessful = true;
-            }
-        } finally {
-            if (useTransaction) {
-                internal.endTransaction();
-
-                // if delete was in transaction and it was successful -> notify about changes
-                if (transactionSuccessful) {
-                    final Set<String> affectedTables = new HashSet<String>(1); // in most cases it will be 1 table
-
-                    for (final T object : results.keySet()) {
-                        affectedTables.addAll(results.get(object).affectedTables());
-                    }
-
-                    // IMPORTANT: Notifying about change should be done after end of transaction
-                    // It'll reduce number of possible deadlock situations
-                    internal.notifyAboutChanges(Changes.newInstance(affectedTables));
-                }
-            }
-        }
-
-        return PutResults.newInstance(results);
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Put Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * put only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Put Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<PutResults<T>> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedPutCollectionOfObjects}
-     *
-     * @param <T> type of objects to put
-     */
-    public static final class Builder<T> {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        @NonNull
-        private final Collection<T> objects;
-
-        private PutResolver<T> putResolver;
-
-        private boolean useTransaction = true;
-
-        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull Collection<T> objects) {
-            this.storIOSQLite = storIOSQLite;
-            this.objects = objects;
-        }
-
-        /**
-         * Optional: Specifies {@link PutResolver} for Put Operation
-         * which allows you to customize behavior of Put Operation
-         * <p/>
-         * Can be set via {@link SQLiteTypeMapping}
-         * If it's not set via {@link SQLiteTypeMapping} or explicitly -> exception will be thrown
-         *
-         * @param putResolver put resolver
-         * @return builder
-         * @see DefaultPutResolver
-         */
-        @NonNull
-        public Builder<T> withPutResolver(@NonNull PutResolver<T> putResolver) {
-            this.putResolver = putResolver;
-            return this;
-        }
-
-        /**
-         * Optional: Defines that Put Operation will use transaction if it is supported by implementation of {@link StorIOSQLite}
-         * <p/>
-         * By default, transaction will be used
-         *
-         * @return builder
-         */
-        @NonNull
-        public Builder<T> useTransaction(boolean useTransaction) {
-            this.useTransaction = useTransaction;
-            return this;
-        }
-
-        /**
-         * Prepares Put Operation
-         *
-         * @return {@link PreparedPutCollectionOfObjects} instance
-         */
-        @NonNull
-        public PreparedPutCollectionOfObjects<T> prepare() {
-            return new PreparedPutCollectionOfObjects<T>(
-                    storIOSQLite,
-                    objects,
-                    putResolver,
-                    useTransaction
-            );
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValues.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValues.java
deleted file mode 100644
index 6a92f3f..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValues.java
+++ /dev/null
@@ -1,146 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.content.ContentValues;
-import android.support.annotation.NonNull;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-import com.pushtorefresh.storio.sqlite.Changes;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Put Operation for {@link StorIOSQLite}.
- */
-public final class PreparedPutContentValues extends PreparedPut<PutResult> {
-
-    @NonNull
-    private final ContentValues contentValues;
-
-    @NonNull
-    private final PutResolver<ContentValues> putResolver;
-
-    PreparedPutContentValues(@NonNull StorIOSQLite storIOSQLite, @NonNull ContentValues contentValues, @NonNull PutResolver<ContentValues> putResolver) {
-        super(storIOSQLite);
-        this.contentValues = contentValues;
-        this.putResolver = putResolver;
-    }
-
-    /**
-     * Executes Put Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null result of Put Operation.
-     */
-    @WorkerThread
-    @NonNull
-    @Override
-    public PutResult executeAsBlocking() {
-        final PutResult putResult = putResolver.performPut(storIOSQLite, contentValues);
-        storIOSQLite.internal().notifyAboutChanges(Changes.newInstance(putResult.affectedTables()));
-        return putResult;
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Put Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * put only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Put Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<PutResult> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedPutContentValues}.
-     */
-    public static final class Builder {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        @NonNull
-        private final ContentValues contentValues;
-
-        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull ContentValues contentValues) {
-            this.storIOSQLite = storIOSQLite;
-            this.contentValues = contentValues;
-        }
-
-        /**
-         * Required: Specifies {@link PutResolver} for Put Operation
-         * which allows you to customize behavior of Put Operation.
-         *
-         * @param putResolver put resolver.
-         * @return builder.
-         * @see DefaultPutResolver
-         */
-        @NonNull
-        public CompleteBuilder withPutResolver(@NonNull PutResolver<ContentValues> putResolver) {
-            checkNotNull(putResolver, "Please specify put resolver");
-
-            return new CompleteBuilder(
-                    storIOSQLite,
-                    contentValues,
-                    putResolver
-            );
-        }
-    }
-
-    /**
-     * Compile-time safe part of {@link Builder}.
-     */
-    public static final class CompleteBuilder {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        @NonNull
-        private final ContentValues contentValues;
-
-        @NonNull
-        private final PutResolver<ContentValues> putResolver;
-
-        CompleteBuilder(@NonNull StorIOSQLite storIOSQLite, @NonNull ContentValues contentValues, @NonNull PutResolver<ContentValues> putResolver) {
-            this.storIOSQLite = storIOSQLite;
-            this.contentValues = contentValues;
-            this.putResolver = putResolver;
-        }
-
-        /**
-         * Prepares Put Operation.
-         *
-         * @return {@link PreparedPutContentValues} instance.
-         */
-        @NonNull
-        public PreparedPutContentValues prepare() {
-            return new PreparedPutContentValues(
-                    storIOSQLite,
-                    contentValues,
-                    putResolver
-            );
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValuesIterable.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValuesIterable.java
deleted file mode 100644
index 6e303b2..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValuesIterable.java
+++ /dev/null
@@ -1,211 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.content.ContentValues;
-import android.support.annotation.NonNull;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-import com.pushtorefresh.storio.sqlite.Changes;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-public final class PreparedPutContentValuesIterable extends PreparedPut<PutResults<ContentValues>> {
-
-    @NonNull
-    private final Iterable<ContentValues> contentValuesIterable;
-
-    @NonNull
-    private final PutResolver<ContentValues> putResolver;
-
-    private final boolean useTransaction;
-
-    PreparedPutContentValuesIterable(
-            @NonNull StorIOSQLite storIOSQLite,
-            @NonNull Iterable<ContentValues> contentValuesIterable,
-            @NonNull PutResolver<ContentValues> putResolver,
-            boolean useTransaction) {
-
-        super(storIOSQLite);
-        this.contentValuesIterable = contentValuesIterable;
-        this.putResolver = putResolver;
-        this.useTransaction = useTransaction;
-    }
-
-    /**
-     * Executes Put Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null results of Put Operation.
-     */
-    @WorkerThread
-    @NonNull
-    @Override
-    public PutResults<ContentValues> executeAsBlocking() {
-        final StorIOSQLite.Internal internal = storIOSQLite.internal();
-
-        final Map<ContentValues, PutResult> putResults = new HashMap<ContentValues, PutResult>();
-
-        if (useTransaction) {
-            internal.beginTransaction();
-        }
-
-        boolean transactionSuccessful = false;
-
-        try {
-            for (ContentValues contentValues : contentValuesIterable) {
-                final PutResult putResult = putResolver.performPut(storIOSQLite, contentValues);
-                putResults.put(contentValues, putResult);
-
-                if (!useTransaction) {
-                    internal.notifyAboutChanges(Changes.newInstance(putResult.affectedTables()));
-                }
-            }
-
-            if (useTransaction) {
-                storIOSQLite.internal().setTransactionSuccessful();
-                transactionSuccessful = true;
-            }
-        } finally {
-            if (useTransaction) {
-                storIOSQLite.internal().endTransaction();
-
-                if (transactionSuccessful) {
-                    final Set<String> affectedTables = new HashSet<String>(1); // in most cases it will be 1 table
-
-                    for (final ContentValues contentValues : putResults.keySet()) {
-                        affectedTables.addAll(putResults.get(contentValues).affectedTables());
-                    }
-
-                    storIOSQLite.internal().notifyAboutChanges(Changes.newInstance(affectedTables));
-                }
-            }
-        }
-
-        return PutResults.newInstance(putResults);
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Put Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * put only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Put Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<PutResults<ContentValues>> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedPutContentValuesIterable}
-     */
-    public static final class Builder {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        @NonNull
-        private final Iterable<ContentValues> contentValuesIterable;
-
-        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull Iterable<ContentValues> contentValuesIterable) {
-            this.storIOSQLite = storIOSQLite;
-            this.contentValuesIterable = contentValuesIterable;
-        }
-
-        /**
-         * Required: Specifies {@link PutResolver} for Put Operation
-         * which allows you to customize behavior of Put Operation
-         *
-         * @param putResolver put resolver
-         * @return builder
-         * @see DefaultPutResolver
-         */
-        @NonNull
-        public CompleteBuilder withPutResolver(@NonNull PutResolver<ContentValues> putResolver) {
-            checkNotNull(putResolver, "Please specify put resolver");
-
-            return new CompleteBuilder(
-                    storIOSQLite,
-                    contentValuesIterable,
-                    putResolver
-            );
-        }
-    }
-
-    /**
-     * Compile-time safe part of {@link Builder}
-     */
-    public static final class CompleteBuilder {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        @NonNull
-        private final Iterable<ContentValues> contentValuesIterable;
-
-        @NonNull
-        private final PutResolver<ContentValues> putResolver;
-
-        private boolean useTransaction = true;
-
-        CompleteBuilder(@NonNull StorIOSQLite storIOSQLite, @NonNull Iterable<ContentValues> contentValuesIterable, @NonNull PutResolver<ContentValues> putResolver) {
-            this.storIOSQLite = storIOSQLite;
-            this.contentValuesIterable = contentValuesIterable;
-            this.putResolver = putResolver;
-        }
-
-        /**
-         * Optional: Defines that Put Operation will use transaction
-         * if it is supported by implementation of {@link StorIOSQLite}
-         * <p/>
-         * By default, transaction will be used
-         *
-         * @return builder
-         */
-        @NonNull
-        public CompleteBuilder useTransaction(boolean useTransaction) {
-            this.useTransaction = useTransaction;
-            return this;
-        }
-
-        /**
-         * Prepares Put Operation
-         *
-         * @return {@link PreparedPutContentValuesIterable} instance
-         */
-        @NonNull
-        public PreparedPutContentValuesIterable prepare() {
-            return new PreparedPutContentValuesIterable(
-                    storIOSQLite,
-                    contentValuesIterable,
-                    putResolver,
-                    useTransaction
-            );
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutObject.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutObject.java
deleted file mode 100644
index fa80bfc..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutObject.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import com.pushtorefresh.storio.operation.internal.OnSubscribeExecuteAsBlocking;
-import com.pushtorefresh.storio.sqlite.Changes;
-import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-
-import rx.Observable;
-import rx.schedulers.Schedulers;
-
-import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
-
-/**
- * Prepared Put Operation for {@link StorIOSQLite}.
- *
- * @param <T> type of object to put.
- */
-public final class PreparedPutObject<T> extends PreparedPut<PutResult> {
-
-    @NonNull
-    private final T object;
-
-    @Nullable
-    private final PutResolver<T> explicitPutResolver;
-
-    PreparedPutObject(@NonNull StorIOSQLite storIOSQLite,
-                      @NonNull T object,
-                      @Nullable PutResolver<T> explicitPutResolver) {
-        super(storIOSQLite);
-        this.object = object;
-        this.explicitPutResolver = explicitPutResolver;
-    }
-
-    /**
-     * Executes Put Operation immediately in current thread.
-     * <p/>
-     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
-     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
-     * So please, call this method on some background thread. See {@link WorkerThread}.
-     *
-     * @return non-null result of Put Operation.
-     */
-    @SuppressWarnings("unchecked")
-    @WorkerThread
-    @NonNull
-    @Override
-    public PutResult executeAsBlocking() {
-        final StorIOSQLite.Internal internal = storIOSQLite.internal();
-
-        final PutResolver<T> putResolver;
-
-        if (explicitPutResolver != null) {
-            putResolver = explicitPutResolver;
-        } else {
-            final SQLiteTypeMapping<T> typeMapping = internal.typeMapping((Class<T>) object.getClass());
-
-            if (typeMapping == null) {
-                throw new IllegalStateException("Object does not have type mapping: " +
-                        "object = " + object + ", object.class = " + object.getClass() + "," +
-                        "db was not affected by this operation, please add type mapping for this type");
-            }
-
-            putResolver = typeMapping.putResolver();
-        }
-
-        final PutResult putResult = putResolver.performPut(storIOSQLite, object);
-        internal.notifyAboutChanges(Changes.newInstance(putResult.affectedTables()));
-        return putResult;
-    }
-
-    /**
-     * Creates {@link Observable} which will perform Put Operation and send result to observer.
-     * <p/>
-     * Returned {@link Observable} will be "Cold Observable", which means that it performs
-     * put only after subscribing to it. Also, it emits the result once.
-     * <p/>
-     * <dl>
-     * <dt><b>Scheduler:</b></dt>
-     * <dd>Operates on {@link Schedulers#io()}.</dd>
-     * </dl>
-     *
-     * @return non-null {@link Observable} which will perform Put Operation.
-     * and send result to observer.
-     */
-    @NonNull
-    @Override
-    public Observable<PutResult> createObservable() {
-        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
-
-        return Observable
-                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
-                .subscribeOn(Schedulers.io());
-    }
-
-    /**
-     * Builder for {@link PreparedPutObject}.
-     *
-     * @param <T> type of object to put.
-     */
-    public static final class Builder<T> {
-
-        @NonNull
-        private final StorIOSQLite storIOSQLite;
-
-        @NonNull
-        private final T object;
-
-        private PutResolver<T> putResolver;
-
-        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull T object) {
-            this.storIOSQLite = storIOSQLite;
-            this.object = object;
-        }
-
-        /**
-         * Optional: Specifies {@link PutResolver} for Put Operation
-         * which allows you to customize behavior of Put Operation.
-         * <p/>
-         * Can be set via {@link SQLiteTypeMapping}
-         * If it's not set via {@link SQLiteTypeMapping} or explicitly -> exception will be thrown.
-         *
-         * @param putResolver put resolver.
-         * @return builder.
-         * @see DefaultPutResolver
-         */
-        @NonNull
-        public Builder<T> withPutResolver(@NonNull PutResolver<T> putResolver) {
-            this.putResolver = putResolver;
-            return this;
-        }
-
-        /**
-         * Prepares Put Operation.
-         *
-         * @return {@link PreparedPutObject} instance.
-         */
-        @NonNull
-        public PreparedPutObject<T> prepare() {
-            return new PreparedPutObject<T>(
-                    storIOSQLite,
-                    object,
-                    putResolver
-            );
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PutResolver.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PutResolver.java
deleted file mode 100644
index 56fb8ad..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PutResolver.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-
-/**
- * Defines behavior of Put Operation (insert or update).
- *
- * @param <T> type of objects to put.
- * @see DefaultPutResolver
- */
-public abstract class PutResolver<T> {
-
-    /**
-     * Performs put of an object.
-     *
-     * @param storIOSQLite {@link StorIOSQLite} instance to perform put into.
-     * @param object       non-null object that should be put into {@link StorIOSQLite}.
-     * @return non-null result of Put Operation.
-     */
-    @NonNull
-    public abstract PutResult performPut(@NonNull StorIOSQLite storIOSQLite, @NonNull T object);
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PutResult.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PutResult.java
deleted file mode 100644
index f899e27..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PutResult.java
+++ /dev/null
@@ -1,182 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import java.util.Collections;
-import java.util.Set;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
-
-/**
- * Immutable container for result of Put Operation.
- * <p>
- * Instances of this class are immutable.
- */
-public class PutResult {
-
-    @Nullable
-    private final Long insertedId;
-
-    @Nullable
-    private final Integer numberOfRowsUpdated;
-
-    @NonNull
-    private final Set<String> affectedTables;
-
-    private PutResult(@Nullable Long insertedId, @Nullable Integer numberOfRowsUpdated, @NonNull Set<String> affectedTables) {
-        checkNotNull(affectedTables, "Please specify affected tables");
-        this.insertedId = insertedId;
-        this.numberOfRowsUpdated = numberOfRowsUpdated;
-        this.affectedTables = Collections.unmodifiableSet(affectedTables);
-    }
-
-    /**
-     * Creates {@link PutResult} of insert.
-     *
-     * @param insertedId     id of new row.
-     * @param affectedTables tables that were affected.
-     * @return new {@link PutResult} instance.
-     */
-    @NonNull
-    public static PutResult newInsertResult(long insertedId, @NonNull Set<String> affectedTables) {
-        return new PutResult(insertedId, null, affectedTables);
-    }
-
-    /**
-     * Creates {@link PutResult} of insert.
-     *
-     * @param insertedId    id of new row.
-     * @param affectedTable table that was affected.
-     * @return new {@link PutResult} instance.
-     */
-    @NonNull
-    public static PutResult newInsertResult(long insertedId, @NonNull String affectedTable) {
-        return new PutResult(insertedId, null, Collections.singleton(affectedTable));
-    }
-
-    /**
-     * Creates {@link PutResult} of update.
-     *
-     * @param numberOfRowsUpdated number of rows that were updated.
-     * @param affectedTables      tables that were affected.
-     * @return new {@link PutResult} instance.
-     */
-    @NonNull
-    public static PutResult newUpdateResult(int numberOfRowsUpdated, @NonNull Set<String> affectedTables) {
-        return new PutResult(null, numberOfRowsUpdated, affectedTables);
-    }
-
-    /**
-     * Creates {@link PutResult} of update.
-     *
-     * @param numberOfRowsUpdated number of rows that were updated.
-     * @param affectedTable       table that was affected.
-     * @return new {@link PutResult} instance.
-     */
-    @NonNull
-    public static PutResult newUpdateResult(int numberOfRowsUpdated, @NonNull String affectedTable) {
-        return new PutResult(null, numberOfRowsUpdated, Collections.singleton(affectedTable));
-    }
-
-    /**
-     * Checks whether result of Put Operation was "insert".
-     *
-     * @return {@code true} if something was inserted into
-     * {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}, {@code false} otherwise.
-     */
-    public boolean wasInserted() {
-        return insertedId != null;
-    }
-
-    /**
-     * Checks whether result of Put Operation was NOT "insert".
-     *
-     * @return {@code true} if nothing was inserted into
-     * {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}, {@code false} if something was inserted.
-     */
-    public boolean wasNotInserted() {
-        return !wasInserted();
-    }
-
-    /**
-     * Checks whether result of Put Operation was "update".
-     *
-     * @return {@code true} if something was updated in
-     * {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}, {@code false} otherwise.
-     */
-    public boolean wasUpdated() {
-        return numberOfRowsUpdated != null;
-    }
-
-    /**
-     * Checks whether result of Put Operation was NOT "update".
-     *
-     * @return {@code true} if nothing was updated in
-     * {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}, {@code false} if something was updated.
-     */
-    public boolean wasNotUpdated() {
-        return !wasUpdated();
-    }
-
-    /**
-     * Gets id of inserted row.
-     *
-     * @return {@code null} if nothing was inserted or id of inserted row.
-     */
-    @Nullable
-    public Long insertedId() {
-        return insertedId;
-    }
-
-    /**
-     * Gets number of rows updated.
-     *
-     * @return {@code null} if nothing was updated or number of updated rows.
-     */
-    @Nullable
-    public Integer numberOfRowsUpdated() {
-        return numberOfRowsUpdated;
-    }
-
-    /**
-     * Gets names of affected tables.
-     *
-     * @return non-null unmodifiable set of affected tables.
-     */
-    @NonNull
-    public Set<String> affectedTables() {
-        return affectedTables;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        PutResult putResult = (PutResult) o;
-
-        if (insertedId != null ? !insertedId.equals(putResult.insertedId) : putResult.insertedId != null)
-            return false;
-        if (numberOfRowsUpdated != null ? !numberOfRowsUpdated.equals(putResult.numberOfRowsUpdated) : putResult.numberOfRowsUpdated != null)
-            return false;
-        return affectedTables.equals(putResult.affectedTables);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = insertedId != null ? insertedId.hashCode() : 0;
-        result = 31 * result + (numberOfRowsUpdated != null ? numberOfRowsUpdated.hashCode() : 0);
-        result = 31 * result + affectedTables.hashCode();
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "PutResult{" +
-                "insertedId=" + insertedId +
-                ", numberOfRowsUpdated=" + numberOfRowsUpdated +
-                ", affectedTables=" + affectedTables +
-                '}';
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PutResults.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PutResults.java
deleted file mode 100644
index 24f9941..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operation/put/PutResults.java
+++ /dev/null
@@ -1,127 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * Immutable container for results of Put Operation.
- * <p>
- * Instances of this class are Immutable
- *
- * @param <T> type of objects that were put.
- */
-public final class PutResults<T> {
-
-    @NonNull
-    private final Map<T, PutResult> results;
-
-    @Nullable
-    private volatile Integer numberOfInsertsCache;
-
-    @Nullable
-    private volatile Integer numberOfUpdatesCache;
-
-    private PutResults(@NonNull Map<T, PutResult> putResults) {
-        this.results = Collections.unmodifiableMap(putResults);
-    }
-
-    /**
-     * Creates new instance of {@link PutResults}.
-     *
-     * @param putResults results of Put Operation.
-     * @param <T>        type of objects.
-     * @return immutable instance of {@link PutResults}.
-     */
-    @NonNull
-    public static <T> PutResults<T> newInstance(@NonNull Map<T, PutResult> putResults) {
-        return new PutResults<T>(putResults);
-    }
-
-    /**
-     * Returns immutable Map of pairs {@code (object, PutResult)}.
-     *
-     * @return immutable Map of pairs {@code (object, PutResult)}.
-     */
-    @NonNull
-    public Map<T, PutResult> results() {
-        return results;
-    }
-
-    /**
-     * Returns number of inserts from all {@link #results()}.
-     *
-     * @return number of inserts from all {@link #results()}.
-     */
-    public int numberOfInserts() {
-        final Integer cachedValue = numberOfInsertsCache;
-
-        if (cachedValue != null) {
-            return cachedValue;
-        }
-
-        int numberOfInserts = 0;
-
-        for (T object : results.keySet()) {
-            if (results.get(object).wasInserted()) {
-                numberOfInserts++;
-            }
-        }
-
-        numberOfInsertsCache = numberOfInserts;
-
-        return numberOfInserts;
-    }
-
-    /**
-     * Returns number of updates from all {@link #results()}.
-     *
-     * @return number of updates from all {@link #results()}.
-     */
-    @SuppressWarnings("ConstantConditions")
-    public int numberOfUpdates() {
-        final Integer cachedValue = numberOfUpdatesCache;
-
-        if (cachedValue != null) {
-            return cachedValue;
-        }
-
-        int numberOfUpdates = 0;
-
-        for (T object : results.keySet()) {
-            final PutResult putResult = results.get(object);
-
-            if (putResult.wasUpdated()) {
-                numberOfUpdates += putResult.numberOfRowsUpdated();
-            }
-        }
-
-        numberOfUpdatesCache = numberOfUpdates;
-
-        return numberOfUpdates;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        PutResults<?> that = (PutResults<?>) o;
-
-        return results.equals(that.results);
-    }
-
-    @Override
-    public int hashCode() {
-        return results.hashCode();
-    }
-
-    @Override
-    public String toString() {
-        return "PutResults{" +
-                "results=" + results +
-                '}';
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DefaultDeleteResolver.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DefaultDeleteResolver.java
new file mode 100644
index 0000000..ddb49be
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DefaultDeleteResolver.java
@@ -0,0 +1,33 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+
+/**
+ * Default implementation of {@link DeleteResolver}.
+ * Thread-safe.
+ */
+public abstract class DefaultDeleteResolver<T> extends DeleteResolver<T> {
+
+    /**
+     * Converts object to {@link DeleteQuery}.
+     *
+     * @param object object that should be deleted.
+     * @return {@link DeleteQuery} that will be performed.
+     */
+    @NonNull
+    protected abstract DeleteQuery mapToDeleteQuery(@NonNull T object);
+
+    /**
+     * {@inheritDoc}
+     */
+    @NonNull
+    @Override
+    public DeleteResult performDelete(@NonNull StorIOSQLite storIOSQLite, @NonNull T object) {
+        final DeleteQuery deleteQuery = mapToDeleteQuery(object);
+        final int numberOfRowsDeleted = storIOSQLite.internal().delete(deleteQuery);
+        return DeleteResult.newInstance(numberOfRowsDeleted, deleteQuery.table());
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResolver.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResolver.java
new file mode 100644
index 0000000..519df2c
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResolver.java
@@ -0,0 +1,23 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+
+/**
+ * Defines behavior of Delete Operation.
+ * <p>
+ * Implementation should be thread-safe!
+ */
+public abstract class DeleteResolver<T> {
+
+    /**
+     * Performs delete of an object.
+     *
+     * @param storIOSQLite {@link StorIOSQLite} instance to perform delete on.
+     * @param object       object that should be deleted.
+     * @return non-null result of Delete Operation.
+     */
+    @NonNull
+    public abstract DeleteResult performDelete(@NonNull StorIOSQLite storIOSQLite, @NonNull T object);
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResult.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResult.java
new file mode 100644
index 0000000..9c04fbf
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResult.java
@@ -0,0 +1,98 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import android.support.annotation.NonNull;
+
+import java.util.Collections;
+import java.util.Set;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+
+/**
+ * Immutable container for result of Delete Operation.
+ * <p>
+ * Instances of this class are Immutable.
+ */
+public final class DeleteResult {
+
+    private final int numberOfRowsDeleted;
+
+    @NonNull
+    private final Set<String> affectedTables;
+
+    private DeleteResult(int numberOfRowsDeleted, @NonNull Set<String> affectedTables) {
+        checkNotNull(affectedTables, "Please specify affected tables");
+        this.numberOfRowsDeleted = numberOfRowsDeleted;
+        this.affectedTables = Collections.unmodifiableSet(affectedTables);
+    }
+
+    /**
+     * Creates new instance of immutable container for results of Delete Operation.
+     *
+     * @param numberOfRowsDeleted number of rows that were deleted.
+     * @param affectedTables      tables that were affected.
+     * @return new instance of immutable container for result of Delete Operation.
+     */
+    @NonNull
+    public static DeleteResult newInstance(int numberOfRowsDeleted, @NonNull Set<String> affectedTables) {
+        checkNotNull(affectedTables, "Please specify affected tables");
+        return new DeleteResult(numberOfRowsDeleted, affectedTables);
+    }
+
+    /**
+     * Creates new instance of immutable container for results of Delete Operation.
+     *
+     * @param numberOfRowsDeleted number of rows that were deleted.
+     * @param affectedTable       table that was affected.
+     * @return new instance of immutable container for results of Delete Operation.
+     */
+    @NonNull
+    public static DeleteResult newInstance(int numberOfRowsDeleted, @NonNull String affectedTable) {
+        checkNotNull(affectedTable, "Please specify affected table");
+        return new DeleteResult(numberOfRowsDeleted, Collections.singleton(affectedTable));
+    }
+
+    /**
+     * Gets number of rows that were deleted.
+     *
+     * @return number of rows that were deleted.
+     */
+    public int numberOfRowsDeleted() {
+        return numberOfRowsDeleted;
+    }
+
+    /**
+     * Gets names of the tables that wer affected by Delete Operation.
+     *
+     * @return unmodifiable set of tables that were affected.
+     */
+    @NonNull
+    public Set<String> affectedTables() {
+        return affectedTables;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        DeleteResult that = (DeleteResult) o;
+
+        if (numberOfRowsDeleted != that.numberOfRowsDeleted) return false;
+        return affectedTables.equals(that.affectedTables);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = numberOfRowsDeleted;
+        result = 31 * result + affectedTables.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "DeleteResult{" +
+                "numberOfRowsDeleted=" + numberOfRowsDeleted +
+                ", affectedTables=" + affectedTables +
+                '}';
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResults.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResults.java
new file mode 100644
index 0000000..d8e37e8
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResults.java
@@ -0,0 +1,90 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import android.support.annotation.NonNull;
+
+import java.util.Collections;
+import java.util.Map;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+
+/**
+ * Immutable container for results of Delete Operation
+ * <p/>
+ * Instances of this class are Immutable
+ *
+ * @param <T> type of objects
+ */
+public class DeleteResults<T> {
+
+    @NonNull
+    private final Map<T, DeleteResult> results;
+
+    private DeleteResults(@NonNull Map<T, DeleteResult> results) {
+        checkNotNull(results, "Please specify Delete Operation results");
+        this.results = Collections.unmodifiableMap(results);
+    }
+
+    /**
+     * Creates new instance of immutable container for results of Delete Operation
+     *
+     * @param results map with results of Delete Operation
+     * @param <T>     type of objects
+     * @return new instance of {@link DeleteResults}
+     */
+    @NonNull
+    public static <T> DeleteResults<T> newInstance(@NonNull Map<T, DeleteResult> results) {
+        return new DeleteResults<T>(results);
+    }
+
+    /**
+     * Returns immutable Map of pairs (object, deleteResult)
+     *
+     * @return immutable Map of pairs (object, deleteResult)
+     */
+    @NonNull
+    public Map<T, DeleteResult> results() {
+        return results;
+    }
+
+    /**
+     * Checks whether particular object was deleted
+     *
+     * @param object object to check
+     * @return true if object was deleted, false otherwise
+     */
+    public boolean wasDeleted(@NonNull T object) {
+        return results.containsKey(object);
+    }
+
+    /**
+     * Checks whether particular object was NOT deleted
+     *
+     * @param object object to check
+     * @return true if object was NOT deleter, false if it was deleted
+     */
+    public boolean wasNotDeleted(@NonNull T object) {
+        return !results.containsKey(object);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        DeleteResults<?> that = (DeleteResults<?>) o;
+
+        return results.equals(that.results);
+    }
+
+    @Override
+    public int hashCode() {
+        return results.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "DeleteResults{" +
+                "results=" + results +
+                '}';
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDelete.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDelete.java
new file mode 100644
index 0000000..bf04bd1
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDelete.java
@@ -0,0 +1,72 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.operations.PreparedOperation;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+
+import java.util.Collection;
+
+/**
+ * Prepared Delete Operation for {@link StorIOSQLite}.
+ *
+ * @param <T> type of object to delete.
+ */
+public abstract class PreparedDelete<T> implements PreparedOperation<T> {
+
+    @NonNull
+    protected final StorIOSQLite storIOSQLite;
+
+    PreparedDelete(@NonNull StorIOSQLite storIOSQLite) {
+        this.storIOSQLite = storIOSQLite;
+    }
+
+    /**
+     * Builder for {@link PreparedDelete}.
+     */
+    public static final class Builder {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        public Builder(@NonNull StorIOSQLite storIOSQLite) {
+            this.storIOSQLite = storIOSQLite;
+        }
+
+        /**
+         * Prepares Delete Operation by {@link com.pushtorefresh.storio.sqlite.queries.DeleteQuery}.
+         *
+         * @param deleteQuery query that specifies which rows should be deleted.
+         * @return builder.
+         */
+        @NonNull
+        public PreparedDeleteByQuery.Builder byQuery(@NonNull DeleteQuery deleteQuery) {
+            return new PreparedDeleteByQuery.Builder(storIOSQLite, deleteQuery);
+        }
+
+        /**
+         * Prepares Delete Operation which should delete one object.
+         *
+         * @param object object to delete.
+         * @param <T>    type of the object.
+         * @return builder.
+         */
+        @NonNull
+        public <T> PreparedDeleteObject.Builder<T> object(@NonNull T object) {
+            return new PreparedDeleteObject.Builder<T>(storIOSQLite, object);
+        }
+
+        /**
+         * Prepares Delete Operation which should delete multiple objects.
+         *
+         * @param objects objects to delete.
+         * @param <T>     type of objects.
+         * @return builder.
+         */
+        @NonNull
+        public <T> PreparedDeleteCollectionOfObjects.Builder<T> objects(@NonNull Collection<T> objects) {
+            return new PreparedDeleteCollectionOfObjects.Builder<T>(storIOSQLite, objects);
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteByQuery.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteByQuery.java
new file mode 100644
index 0000000..3c29156
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteByQuery.java
@@ -0,0 +1,131 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+import com.pushtorefresh.storio.sqlite.Changes;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Delete Operation for {@link StorIOSQLite}.
+ */
+public final class PreparedDeleteByQuery extends PreparedDelete<DeleteResult> {
+
+    @NonNull
+    private final DeleteQuery deleteQuery;
+
+    @NonNull
+    private final DeleteResolver<DeleteQuery> deleteResolver;
+
+    PreparedDeleteByQuery(@NonNull StorIOSQLite storIOSQLite, @NonNull DeleteQuery deleteQuery, @NonNull DeleteResolver<DeleteQuery> deleteResolver) {
+        super(storIOSQLite);
+        this.deleteQuery = deleteQuery;
+        this.deleteResolver = deleteResolver;
+    }
+
+    /**
+     * Executes Delete Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null result of Delete Operation.
+     */
+    @WorkerThread
+    @NonNull
+    @Override
+    public DeleteResult executeAsBlocking() {
+        final DeleteResult deleteResult = deleteResolver.performDelete(storIOSQLite, deleteQuery);
+        storIOSQLite.internal().notifyAboutChanges(Changes.newInstance(deleteResult.affectedTables()));
+        return deleteResult;
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Delete Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * delete only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Delete Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<DeleteResult> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedDeleteByQuery}.
+     */
+    public static final class Builder {
+
+        private static final DeleteResolver<DeleteQuery> STANDARD_DELETE_RESOLVER = new DefaultDeleteResolver<DeleteQuery>() {
+            @NonNull
+            @Override
+            public DeleteQuery mapToDeleteQuery(@NonNull DeleteQuery deleteQuery) {
+                return deleteQuery; // no transformations
+            }
+        };
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        @NonNull
+        private final DeleteQuery deleteQuery;
+
+        private DeleteResolver<DeleteQuery> deleteResolver;
+
+        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull DeleteQuery deleteQuery) {
+            this.storIOSQLite = storIOSQLite;
+            this.deleteQuery = deleteQuery;
+        }
+
+        /**
+         * Optional: Specifies Delete Resolver for Delete Operation.
+         * <p/>
+         * If no value was specified, builder will use resolver that
+         * simply redirects query to {@link StorIOSQLite}.
+         *
+         * @param deleteResolver nullable resolver for Delete Operation.
+         * @return builder.
+         */
+        @NonNull
+        public Builder withDeleteResolver(@Nullable DeleteResolver<DeleteQuery> deleteResolver) {
+            this.deleteResolver = deleteResolver;
+            return this;
+        }
+
+        /**
+         * Prepares Delete Operation.
+         *
+         * @return {@link PreparedDeleteByQuery} instance.
+         */
+        @NonNull
+        public PreparedDeleteByQuery prepare() {
+            if (deleteResolver == null) {
+                deleteResolver = STANDARD_DELETE_RESOLVER;
+            }
+
+            return new PreparedDeleteByQuery(storIOSQLite, deleteQuery, deleteResolver);
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteCollectionOfObjects.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteCollectionOfObjects.java
new file mode 100644
index 0000000..5db0e02
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteCollectionOfObjects.java
@@ -0,0 +1,244 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+import com.pushtorefresh.storio.sqlite.Changes;
+import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Delete Operation for {@link StorIOSQLite}.
+ *
+ * @param <T> type of objects to delete.
+ */
+public final class PreparedDeleteCollectionOfObjects<T> extends PreparedDelete<DeleteResults<T>> {
+
+    @NonNull
+    private final Collection<T> objects;
+
+    @Nullable
+    private final DeleteResolver<T> explicitDeleteResolver;
+
+    private final boolean useTransaction;
+
+    PreparedDeleteCollectionOfObjects(@NonNull StorIOSQLite storIOSQLite,
+                                      @NonNull Collection<T> objects,
+                                      @Nullable DeleteResolver<T> explicitDeleteResolver,
+                                      boolean useTransaction) {
+        super(storIOSQLite);
+        this.objects = objects;
+        this.explicitDeleteResolver = explicitDeleteResolver;
+        this.useTransaction = useTransaction;
+    }
+
+    /**
+     * Executes Delete Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null results of Delete Operation.
+     */
+    @SuppressWarnings("unchecked")
+    @WorkerThread
+    @NonNull
+    @Override
+    public DeleteResults<T> executeAsBlocking() {
+        final StorIOSQLite.Internal internal = storIOSQLite.internal();
+
+        // Nullable
+        final List<SimpleImmutableEntry<T, DeleteResolver<T>>> objectsAndDeleteResolvers;
+
+        if (explicitDeleteResolver != null) {
+            objectsAndDeleteResolvers = null;
+        } else {
+            objectsAndDeleteResolvers
+                    = new ArrayList<SimpleImmutableEntry<T, DeleteResolver<T>>>(objects.size());
+
+            for (final T object : objects) {
+                final SQLiteTypeMapping<T> typeMapping
+                        = (SQLiteTypeMapping<T>) internal.typeMapping(object.getClass());
+
+                if (typeMapping == null) {
+                    throw new IllegalStateException("One of the objects from the collection does not have type mapping: " +
+                            "object = " + object + ", object.class = " + object.getClass() + "," +
+                            "db was not affected by this operation, please add type mapping for this type");
+                }
+
+                objectsAndDeleteResolvers.add(new SimpleImmutableEntry<T, DeleteResolver<T>>(
+                        object,
+                        typeMapping.deleteResolver()
+                ));
+            }
+        }
+
+        if (useTransaction) {
+            internal.beginTransaction();
+        }
+
+        final Map<T, DeleteResult> results = new HashMap<T, DeleteResult>(objects.size());
+        boolean transactionSuccessful = false;
+
+        try {
+            if (explicitDeleteResolver != null) {
+                for (final T object : objects) {
+                    final DeleteResult deleteResult = explicitDeleteResolver.performDelete(storIOSQLite, object);
+
+                    results.put(object, deleteResult);
+
+                    if (!useTransaction) {
+                        internal.notifyAboutChanges(Changes.newInstance(deleteResult.affectedTables()));
+                    }
+                }
+            } else {
+                for (final SimpleImmutableEntry<T, DeleteResolver<T>> objectAndDeleteResolver : objectsAndDeleteResolvers) {
+                    final T object = objectAndDeleteResolver.getKey();
+                    final DeleteResolver<T> deleteResolver = objectAndDeleteResolver.getValue();
+
+                    final DeleteResult deleteResult = deleteResolver.performDelete(storIOSQLite, object);
+
+                    results.put(object, deleteResult);
+
+                    if (!useTransaction) {
+                        internal.notifyAboutChanges(Changes.newInstance(deleteResult.affectedTables()));
+                    }
+                }
+            }
+
+            if (useTransaction) {
+                internal.setTransactionSuccessful();
+                transactionSuccessful = true;
+            }
+        } finally {
+            if (useTransaction) {
+                internal.endTransaction();
+
+                // if delete was in transaction and it was successful -> notify about changes
+                if (transactionSuccessful) {
+                    final Set<String> affectedTables = new HashSet<String>(1); // in most cases it will be one table
+
+                    for (final T object : results.keySet()) {
+                        affectedTables.addAll(results.get(object).affectedTables());
+                    }
+
+                    // IMPORTANT: Notifying about change should be done after end of transaction
+                    // It'll reduce number of possible deadlock situations
+                    internal.notifyAboutChanges(Changes.newInstance(affectedTables));
+                }
+            }
+        }
+
+        return DeleteResults.newInstance(results);
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Delete Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * delete only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Delete Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<DeleteResults<T>> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedDeleteCollectionOfObjects}.
+     *
+     * @param <T> type of objects to delete.
+     */
+    public static final class Builder<T> {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        @NonNull
+        private final Collection<T> objects;
+
+        private DeleteResolver<T> deleteResolver;
+
+        private boolean useTransaction = true;
+
+        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull Collection<T> objects) {
+            this.storIOSQLite = storIOSQLite;
+            this.objects = objects;
+        }
+
+        /**
+         * Optional: Defines that Delete Operation will use transaction or not.
+         * <p/>
+         * By default, transaction will be used.
+         *
+         * @param useTransaction {@code true} to use transaction, {@code false} to not.
+         * @return builder.
+         */
+        @NonNull
+        public Builder<T> useTransaction(boolean useTransaction) {
+            this.useTransaction = useTransaction;
+            return this;
+        }
+
+        /**
+         * Optional: Specifies {@link DeleteResolver} for Delete Operation.
+         * <p/>
+         * <p/>
+         * Can be set via {@link SQLiteTypeMapping},
+         * If value is not set via {@link SQLiteTypeMapping}
+         * or explicitly -> exception will be thrown.
+         *
+         * @param deleteResolver {@link DeleteResolver} for Delete Operation.
+         * @return builder.
+         */
+        @NonNull
+        public Builder<T> withDeleteResolver(@Nullable DeleteResolver<T> deleteResolver) {
+            this.deleteResolver = deleteResolver;
+            return this;
+        }
+
+        /**
+         * Prepares Delete Operation.
+         *
+         * @return {@link PreparedDeleteCollectionOfObjects}.
+         */
+        @NonNull
+        public PreparedDeleteCollectionOfObjects<T> prepare() {
+            return new PreparedDeleteCollectionOfObjects<T>(
+                    storIOSQLite,
+                    objects,
+                    deleteResolver,
+                    useTransaction
+            );
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteObject.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteObject.java
new file mode 100644
index 0000000..1cf7005
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteObject.java
@@ -0,0 +1,150 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+import com.pushtorefresh.storio.sqlite.Changes;
+import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Delete Operation for {@link StorIOSQLite}.
+ *
+ * @param <T> type of object to delete.
+ */
+public final class PreparedDeleteObject<T> extends PreparedDelete<DeleteResult> {
+
+    @NonNull
+    private final T object;
+
+    @Nullable
+    private final DeleteResolver<T> explicitDeleteResolver;
+
+    PreparedDeleteObject(@NonNull StorIOSQLite storIOSQLite,
+                         @NonNull T object,
+                         @Nullable DeleteResolver<T> explicitDeleteResolver) {
+        super(storIOSQLite);
+        this.object = object;
+        this.explicitDeleteResolver = explicitDeleteResolver;
+    }
+
+    /**
+     * Executes Delete Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null result of Delete Operation.
+     */
+    @SuppressWarnings("unchecked")
+    @WorkerThread
+    @NonNull
+    @Override
+    public DeleteResult executeAsBlocking() {
+        final StorIOSQLite.Internal internal = storIOSQLite.internal();
+
+        final DeleteResolver<T> deleteResolver;
+
+        if (explicitDeleteResolver != null) {
+            deleteResolver = explicitDeleteResolver;
+        } else {
+            final SQLiteTypeMapping<T> typeMapping
+                    = internal.typeMapping((Class<T>) object.getClass());
+
+            if (typeMapping == null) {
+                throw new IllegalStateException("Object does not have type mapping: " +
+                        "object = " + object + ", object.class = " + object.getClass() + "," +
+                        "db was not affected by this operation, please add type mapping for this type");
+            }
+
+            deleteResolver = typeMapping.deleteResolver();
+        }
+
+        final DeleteResult deleteResult = deleteResolver.performDelete(storIOSQLite, object);
+        internal.notifyAboutChanges(Changes.newInstance(deleteResult.affectedTables()));
+        return deleteResult;
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Delete Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * delete only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Delete Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<DeleteResult> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedDeleteObject}.
+     *
+     * @param <T> type of object to delete.
+     */
+    public static final class Builder<T> {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        @NonNull
+        private final T object;
+
+        private DeleteResolver<T> deleteResolver;
+
+        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull T object) {
+            this.storIOSQLite = storIOSQLite;
+            this.object = object;
+        }
+
+        /**
+         * Optional: Specifies {@link DeleteResolver} for Delete Operation.
+         * <p/>
+         * Can be set via {@link SQLiteTypeMapping},
+         * If resolver is not set via {@link SQLiteTypeMapping}
+         * or explicitly -> exception will be thrown.
+         *
+         * @param deleteResolver delete resolver.
+         * @return builder.
+         */
+        @NonNull
+        public Builder<T> withDeleteResolver(@NonNull DeleteResolver<T> deleteResolver) {
+            this.deleteResolver = deleteResolver;
+            return this;
+        }
+
+        /**
+         * Prepares Delete Operation.
+         *
+         * @return {@link PreparedDeleteObject} instance.
+         */
+        @NonNull
+        public PreparedDeleteObject<T> prepare() {
+            return new PreparedDeleteObject<T>(
+                    storIOSQLite,
+                    object,
+                    deleteResolver
+            );
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/execute/PreparedExecuteSQL.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/execute/PreparedExecuteSQL.java
new file mode 100644
index 0000000..9c71821
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/execute/PreparedExecuteSQL.java
@@ -0,0 +1,146 @@
+package com.pushtorefresh.storio.sqlite.operations.execute;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.operations.PreparedOperation;
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+import com.pushtorefresh.storio.sqlite.Changes;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
+
+import java.util.Set;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Execute SQL Operation for {@link StorIOSQLite}.
+ */
+public final class PreparedExecuteSQL implements PreparedOperation<Object> {
+
+    @NonNull
+    private final StorIOSQLite storIOSQLite;
+
+    @NonNull
+    private final RawQuery rawQuery;
+
+    PreparedExecuteSQL(@NonNull StorIOSQLite storIOSQLite, @NonNull RawQuery rawQuery) {
+        this.storIOSQLite = storIOSQLite;
+        this.rawQuery = rawQuery;
+    }
+
+    /**
+     * Executes SQL Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return just a new instance of {@link Object}, actually Execute SQL should return {@code void},
+     * but we can not return instance of {@link Void} so we just return {@link Object}
+     * and you don't have to deal with {@code null}.
+     */
+    @WorkerThread
+    @NonNull
+    @Override
+    public Object executeAsBlocking() {
+        storIOSQLite.internal().executeSQL(rawQuery);
+
+        final Set<String> affectedTables = rawQuery.affectsTables();
+
+        if (affectedTables.size() > 0) {
+            storIOSQLite.internal().notifyAboutChanges(Changes.newInstance(affectedTables));
+        }
+
+        return new Object();
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Execute SQL Operation
+     * and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * execution of SQL only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Delete Operation
+     * and send result to observer. Result: just a new instance of {@link Object},
+     * actually Execute SQL should return {@code void},
+     * but we can not return instance of {@link Void} so we just return {@link Object}
+     * and you don't have to deal with {@code null}.
+     */
+    @NonNull
+    @Override
+    public Observable<Object> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedExecuteSQL}.
+     */
+    public static final class Builder {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        public Builder(@NonNull StorIOSQLite storIOSQLite) {
+            this.storIOSQLite = storIOSQLite;
+        }
+
+        /**
+         * Required: Specifies query for ExecSql Operation.
+         *
+         * @param rawQuery any SQL query that you want to execute, but please, be careful with it.
+         *                 Don't forget that you can set affected tables to the {@link RawQuery},
+         *                 so ExecSQL operation will send notification about changes in that tables.
+         * @return builder.
+         */
+        @NonNull
+        public CompleteBuilder withQuery(@NonNull RawQuery rawQuery) {
+            checkNotNull(rawQuery, "Please set query object");
+            return new CompleteBuilder(storIOSQLite, rawQuery);
+        }
+    }
+
+    /**
+     * Compile-time safe part of {@link Builder}.
+     */
+    public static final class CompleteBuilder {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        @NonNull
+        private final RawQuery rawQuery;
+
+        CompleteBuilder(@NonNull StorIOSQLite storIOSQLite, @NonNull RawQuery rawQuery) {
+            this.storIOSQLite = storIOSQLite;
+            this.rawQuery = rawQuery;
+        }
+
+        /**
+         * Prepares ExecSql Operation.
+         *
+         * @return {@link PreparedExecuteSQL} instance.
+         */
+        @NonNull
+        public PreparedExecuteSQL prepare() {
+            return new PreparedExecuteSQL(
+                    storIOSQLite,
+                    rawQuery
+            );
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/DefaultGetResolver.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/DefaultGetResolver.java
new file mode 100644
index 0000000..006b54b
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/DefaultGetResolver.java
@@ -0,0 +1,36 @@
+package com.pushtorefresh.storio.sqlite.operations.get;
+
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
+
+/**
+ * Default implementation of {@link GetResolver}.
+ * <p>
+ * Thread-safe.
+ * <p>
+ * You need to just override mapping from Cursor.
+ */
+public abstract class DefaultGetResolver<T> extends GetResolver<T> {
+
+    /**
+     * {@inheritDoc}
+     */
+    @NonNull
+    @Override
+    public Cursor performGet(@NonNull StorIOSQLite storIOSQLite, @NonNull RawQuery rawQuery) {
+        return storIOSQLite.internal().rawQuery(rawQuery);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @NonNull
+    @Override
+    public Cursor performGet(@NonNull StorIOSQLite storIOSQLite, @NonNull Query query) {
+        return storIOSQLite.internal().query(query);
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/GetResolver.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/GetResolver.java
new file mode 100644
index 0000000..87e3cc7
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/GetResolver.java
@@ -0,0 +1,48 @@
+package com.pushtorefresh.storio.sqlite.operations.get;
+
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
+
+/**
+ * Defines behavior of Get Operation.
+ * <p>
+ * Implementation should be thread-safe!
+ */
+public abstract class GetResolver<T> {
+
+    /**
+     * Converts {@link Cursor} with already set position to object of required type.
+     *
+     * @param cursor not closed {@link Cursor} with already set position
+     *               that should be parsed and converted to object of required type.
+     * @return non-null object of required type with data parsed from passed {@link Cursor}.
+     */
+    @NonNull
+    public abstract T mapFromCursor(@NonNull Cursor cursor);
+
+    /**
+     * Performs get of results with passed query.
+     *
+     * @param storIOSQLite {@link StorIOSQLite} instance to perform get from.
+     * @param rawQuery     query that should be performed.
+     * @return non-null, not closed {@link Cursor} that can be empty
+     * or contain data with results of Get Operation.
+     */
+    @NonNull
+    public abstract Cursor performGet(@NonNull StorIOSQLite storIOSQLite, @NonNull RawQuery rawQuery);
+
+    /**
+     * Performs get of results with passed query.
+     *
+     * @param storIOSQLite {@link StorIOSQLite} instance to perform get from.
+     * @param query        query that should be performed.
+     * @return non-null, not closed {@link Cursor} that can be empty
+     * or contain data with results of Get Operation.
+     */
+    @NonNull
+    public abstract Cursor performGet(@NonNull StorIOSQLite storIOSQLite, @NonNull Query query);
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGet.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGet.java
new file mode 100644
index 0000000..89a106b
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGet.java
@@ -0,0 +1,74 @@
+package com.pushtorefresh.storio.sqlite.operations.get;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.pushtorefresh.storio.operations.PreparedOperation;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
+
+/**
+ * Prepared Get Operation for {@link StorIOSQLite}.
+ *
+ * @param <Result> type of result.
+ */
+public abstract class PreparedGet<Result> implements PreparedOperation<Result> {
+
+    @NonNull
+    protected final StorIOSQLite storIOSQLite;
+
+    @Nullable
+    protected final Query query;
+
+    @Nullable
+    protected final RawQuery rawQuery;
+
+    PreparedGet(@NonNull StorIOSQLite storIOSQLite, @NonNull Query query) {
+        this.storIOSQLite = storIOSQLite;
+        this.query = query;
+        this.rawQuery = null;
+    }
+
+    PreparedGet(@NonNull StorIOSQLite storIOSQLite, @NonNull RawQuery rawQuery) {
+        this.storIOSQLite = storIOSQLite;
+        this.rawQuery = rawQuery;
+        query = null;
+    }
+
+    /**
+     * Builder for {@link PreparedGet}.
+     */
+    public static final class Builder {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        public Builder(@NonNull StorIOSQLite storIOSQLite) {
+            this.storIOSQLite = storIOSQLite;
+        }
+
+        /**
+         * Returns builder for Get Operation that returns result as {@link android.database.Cursor}.
+         *
+         * @return builder for Get Operation that returns result as {@link android.database.Cursor}.
+         */
+        @NonNull
+        public PreparedGetCursor.Builder cursor() {
+            return new PreparedGetCursor.Builder(storIOSQLite);
+        }
+
+        /**
+         * Returns builder for Get Operation that returns result as {@link java.util.List} of items.
+         *
+         * @param type type of items.
+         * @param <T>  type of items.
+         * @return builder for Get Operation that returns result as {@link java.util.List} of items.
+         */
+        @NonNull
+        public <T> PreparedGetListOfObjects.Builder<T> listOfObjects(@NonNull Class<T> type) {
+            return new PreparedGetListOfObjects.Builder<T>(storIOSQLite, type);
+        }
+    }
+
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetCursor.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetCursor.java
new file mode 100644
index 0000000..65a2803
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetCursor.java
@@ -0,0 +1,224 @@
+package com.pushtorefresh.storio.sqlite.operations.get;
+
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.operations.internal.MapSomethingToExecuteAsBlocking;
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Get Operation for {@link StorIOSQLite}.
+ */
+public final class PreparedGetCursor extends PreparedGet<Cursor> {
+
+    @NonNull
+    private final GetResolver<Cursor> getResolver;
+
+    PreparedGetCursor(@NonNull StorIOSQLite storIOSQLite,
+                      @NonNull Query query,
+                      @NonNull GetResolver<Cursor> getResolver) {
+        super(storIOSQLite, query);
+        this.getResolver = getResolver;
+    }
+
+    PreparedGetCursor(@NonNull StorIOSQLite storIOSQLite,
+                      @NonNull RawQuery rawQuery,
+                      @NonNull GetResolver<Cursor> getResolver) {
+        super(storIOSQLite, rawQuery);
+        this.getResolver = getResolver;
+    }
+
+    /**
+     * Executes Get Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null {@link Cursor}, can be empty.
+     */
+    @WorkerThread
+    @NonNull
+    public Cursor executeAsBlocking() {
+        if (query != null) {
+            return getResolver.performGet(storIOSQLite, query);
+        } else if (rawQuery != null) {
+            return getResolver.performGet(storIOSQLite, rawQuery);
+        } else {
+            throw new IllegalStateException("Please specify query");
+        }
+    }
+
+    /**
+     * Creates "Hot" {@link Observable} which will be subscribed to changes of tables from query
+     * and will emit result each time change occurs.
+     * <p/>
+     * First result will be emitted immediately after subscription,
+     * other emissions will occur only if changes of tables from query will occur during lifetime of
+     * the {@link Observable}.
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     * <p/>
+     * Please don't forget to unsubscribe from this {@link Observable} because
+     * it's "Hot" and endless.
+     *
+     * @return non-null {@link Observable} which will emit non-null
+     * list with mapped results and will be subscribed to changes of tables from query.
+     */
+    @NonNull
+    @Override
+    public Observable<Cursor> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        final Set<String> tables;
+
+        if (query != null) {
+            tables = new HashSet<String>(1);
+            tables.add(query.table());
+        } else if (rawQuery != null) {
+            tables = rawQuery.observesTables();
+        } else {
+            throw new IllegalStateException("Please specify query");
+        }
+
+        if (!tables.isEmpty()) {
+            return storIOSQLite
+                    .observeChangesInTables(tables) // each change triggers executeAsBlocking
+                    .map(MapSomethingToExecuteAsBlocking.newInstance(this))
+                    .startWith(Observable.create(OnSubscribeExecuteAsBlocking.newInstance(this))) // start stream with first query result
+                    .subscribeOn(Schedulers.io());
+        } else {
+            return Observable
+                    .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                    .subscribeOn(Schedulers.io());
+        }
+    }
+
+    /**
+     * Builder for {@link PreparedGetCursor}.
+     * <p/>
+     * Required: You should specify query by call
+     * {@link #withQuery(Query)} or {@link #withQuery(RawQuery)}.
+     */
+    public static final class Builder {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        Builder(@NonNull StorIOSQLite storIOSQLite) {
+            this.storIOSQLite = storIOSQLite;
+        }
+
+        /**
+         * Required: Specifies {@link Query} for Get Operation.
+         *
+         * @param query query.
+         * @return builder.
+         * @see Query
+         */
+        @NonNull
+        public CompleteBuilder withQuery(@NonNull Query query) {
+            checkNotNull(query, "Please specify query");
+            return new CompleteBuilder(storIOSQLite, query);
+        }
+
+        /**
+         * Required: Specifies {@link RawQuery} for Get Operation,
+         * you can use it for "joins" and same constructions which are not allowed for {@link Query}.
+         *
+         * @param rawQuery query.
+         * @return builder.
+         * @see RawQuery
+         */
+        @NonNull
+        public CompleteBuilder withQuery(@NonNull RawQuery rawQuery) {
+            checkNotNull(rawQuery, "Please specify rawQuery");
+            return new CompleteBuilder(storIOSQLite, rawQuery);
+        }
+    }
+
+    /**
+     * Compile-time safe part of builder for {@link PreparedGetCursor}.
+     */
+    public static final class CompleteBuilder {
+
+        private static final GetResolver<Cursor> STANDARD_GET_RESOLVER = new DefaultGetResolver<Cursor>() {
+            @NonNull
+            @Override
+            public Cursor mapFromCursor(@NonNull Cursor cursor) {
+                return cursor; // no modifications
+            }
+        };
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        private final Query query;
+
+        private final RawQuery rawQuery;
+
+        private GetResolver<Cursor> getResolver;
+
+        CompleteBuilder(@NonNull StorIOSQLite storIOSQLite, @NonNull Query query) {
+            this.storIOSQLite = storIOSQLite;
+            this.query = query;
+            this.rawQuery = null;
+        }
+
+        CompleteBuilder(@NonNull StorIOSQLite storIOSQLite, @NonNull RawQuery rawQuery) {
+            this.storIOSQLite = storIOSQLite;
+            this.rawQuery = rawQuery;
+            this.query = null;
+        }
+
+        /**
+         * Optional: Specifies Get Resolver for operation.
+         * If no value is set, builder will use resolver that
+         * simply redirects query to {@link StorIOSQLite}.
+         *
+         * @param getResolver nullable GetResolver for Get Operation.
+         * @return builder.
+         */
+        @NonNull
+        public CompleteBuilder withGetResolver(@Nullable GetResolver<Cursor> getResolver) {
+            this.getResolver = getResolver;
+            return this;
+        }
+
+        /**
+         * Prepares Get Operation.
+         *
+         * @return {@link PreparedGetCursor} instance.
+         */
+        @NonNull
+        public PreparedGetCursor prepare() {
+            if (getResolver == null) {
+                getResolver = STANDARD_GET_RESOLVER;
+            }
+
+            if (query != null) {
+                return new PreparedGetCursor(storIOSQLite, query, getResolver);
+            } else if (rawQuery != null) {
+                return new PreparedGetCursor(storIOSQLite, rawQuery, getResolver);
+            } else {
+                throw new IllegalStateException("Please specify query");
+            }
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetListOfObjects.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetListOfObjects.java
new file mode 100644
index 0000000..c01ee70
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetListOfObjects.java
@@ -0,0 +1,292 @@
+package com.pushtorefresh.storio.sqlite.operations.get;
+
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.operations.internal.MapSomethingToExecuteAsBlocking;
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+import static java.util.Collections.EMPTY_LIST;
+import static java.util.Collections.unmodifiableList;
+
+/**
+ * Prepared Get Operation for {@link StorIOSQLite}.
+ *
+ * @param <T> type of results.
+ */
+public final class PreparedGetListOfObjects<T> extends PreparedGet<List<T>> {
+
+    @NonNull
+    private final Class<T> type;
+
+    @Nullable
+    private final GetResolver<T> explicitGetResolver;
+
+    PreparedGetListOfObjects(@NonNull StorIOSQLite storIOSQLite,
+                             @NonNull Class<T> type,
+                             @NonNull Query query,
+                             @Nullable GetResolver<T> explicitGetResolver) {
+        super(storIOSQLite, query);
+        this.type = type;
+        this.explicitGetResolver = explicitGetResolver;
+    }
+
+    PreparedGetListOfObjects(@NonNull StorIOSQLite storIOSQLite,
+                             @NonNull Class<T> type,
+                             @NonNull RawQuery rawQuery,
+                             @Nullable GetResolver<T> explicitGetResolver) {
+        super(storIOSQLite, rawQuery);
+        this.type = type;
+        this.explicitGetResolver = explicitGetResolver;
+    }
+
+    /**
+     * Executes Get Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null, immutable {@link List} with mapped results, list can be empty.
+     */
+    @WorkerThread
+    @SuppressWarnings({"TryFinallyCanBeTryWithResources", "unchecked"})
+    // Min SDK :( unchecked for empty list
+    @NonNull
+    @Override
+    public List<T> executeAsBlocking() {
+        final GetResolver<T> getResolver;
+
+        if (explicitGetResolver != null) {
+            getResolver = explicitGetResolver;
+        } else {
+            final SQLiteTypeMapping<T> typeMapping = storIOSQLite.internal().typeMapping(type);
+
+            if (typeMapping == null) {
+                throw new IllegalStateException("This type does not have type mapping: " +
+                        "type = " + type + "," +
+                        "db was not touched by this operation, please add type mapping for this type");
+            }
+
+            getResolver = typeMapping.getResolver();
+        }
+
+        final Cursor cursor;
+
+        if (query != null) {
+            cursor = getResolver.performGet(storIOSQLite, query);
+        } else if (rawQuery != null) {
+            cursor = getResolver.performGet(storIOSQLite, rawQuery);
+        } else {
+            throw new IllegalStateException("Please specify query");
+        }
+
+        try {
+            final int count = cursor.getCount();
+
+            if (count == 0) {
+                return EMPTY_LIST; // it's immutable
+            }
+
+            final List<T> list = new ArrayList<T>(count);
+
+            while (cursor.moveToNext()) {
+                list.add(getResolver.mapFromCursor(cursor));
+            }
+
+            return unmodifiableList(list);
+        } finally {
+            cursor.close();
+        }
+    }
+
+    /**
+     * Creates "Hot" {@link Observable} which will be subscribed to changes of tables from query
+     * and will emit result each time change occurs.
+     * <p/>
+     * First result will be emitted immediately after subscription,
+     * other emissions will occur only if changes of tables from query will occur during lifetime of
+     * the {@link Observable}.
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     * <p/>
+     * Please don't forget to unsubscribe from this {@link Observable} because
+     * it's "Hot" and endless.
+     *
+     * @return non-null {@link Observable} which will emit non-null, immutable
+     * {@link List} with mapped results and will be subscribed to changes of tables from query,
+     * list can be empty.
+     */
+    @NonNull
+    @Override
+    public Observable<List<T>> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        final Set<String> tables;
+
+        if (query != null) {
+            tables = Collections.singleton(query.table());
+        } else if (rawQuery != null) {
+            tables = rawQuery.observesTables();
+        } else {
+            throw new IllegalStateException("Please specify query");
+        }
+
+        if (!tables.isEmpty()) {
+            return storIOSQLite
+                    .observeChangesInTables(tables) // each change triggers executeAsBlocking
+                    .map(MapSomethingToExecuteAsBlocking.newInstance(this))
+                    .startWith(Observable.create(OnSubscribeExecuteAsBlocking.newInstance(this))) // start stream with first query result
+                    .subscribeOn(Schedulers.io());
+        } else {
+            return Observable
+                    .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                    .subscribeOn(Schedulers.io());
+        }
+    }
+
+    /**
+     * Builder for {@link PreparedGetListOfObjects} Operation.
+     *
+     * @param <T> type of objects.
+     */
+    public static final class Builder<T> {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        @NonNull
+        private final Class<T> type;
+
+        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull Class<T> type) {
+            this.storIOSQLite = storIOSQLite;
+            this.type = type;
+        }
+
+        /**
+         * Required: Specifies query which will be passed to {@link StorIOSQLite}
+         * to get list of objects.
+         *
+         * @param query non-null query.
+         * @return builder.
+         * @see Query
+         */
+        @NonNull
+        public CompleteBuilder<T> withQuery(@NonNull Query query) {
+            checkNotNull(query, "Please specify query");
+            return new CompleteBuilder<T>(storIOSQLite, type, query);
+        }
+
+        /**
+         * Required: Specifies {@link RawQuery} for Get Operation,
+         * you can use it for "joins" and same constructions which are not allowed for {@link Query}.
+         *
+         * @param rawQuery query.
+         * @return builder.
+         * @see RawQuery
+         */
+        @NonNull
+        public CompleteBuilder<T> withQuery(@NonNull RawQuery rawQuery) {
+            checkNotNull(rawQuery, "Please specify rawQuery");
+            return new CompleteBuilder<T>(storIOSQLite, type, rawQuery);
+        }
+    }
+
+    /**
+     * Compile-safe part of {@link Builder}.
+     *
+     * @param <T> type of objects.
+     */
+    public static final class CompleteBuilder<T> {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        @NonNull
+        private final Class<T> type;
+
+        @Nullable
+        private final Query query;
+
+        @Nullable
+        private final RawQuery rawQuery;
+
+        @Nullable
+        private GetResolver<T> getResolver;
+
+        CompleteBuilder(@NonNull StorIOSQLite storIOSQLite, @NonNull Class<T> type, @NonNull Query query) {
+            this.storIOSQLite = storIOSQLite;
+            this.type = type;
+            this.query = query;
+            rawQuery = null;
+        }
+
+        CompleteBuilder(@NonNull StorIOSQLite storIOSQLite, @NonNull Class<T> type, @NonNull RawQuery rawQuery) {
+            this.storIOSQLite = storIOSQLite;
+            this.type = type;
+            this.rawQuery = rawQuery;
+            query = null;
+        }
+
+        /**
+         * Optional: Specifies resolver for Get Operation which can be used
+         * to provide custom behavior of Get Operation.
+         * <p/>
+         * {@link SQLiteTypeMapping} can be used to set default GetResolver.
+         * If GetResolver is not set via {@link SQLiteTypeMapping}
+         * or explicitly -> exception will be thrown.
+         *
+         * @param getResolver nullable resolver for Get Operation.
+         * @return builder.
+         */
+        @NonNull
+        public CompleteBuilder<T> withGetResolver(@Nullable GetResolver<T> getResolver) {
+            this.getResolver = getResolver;
+            return this;
+        }
+
+        /**
+         * Builds new instance of {@link PreparedGetListOfObjects}.
+         *
+         * @return new instance of {@link PreparedGetListOfObjects}.
+         */
+        @NonNull
+        public PreparedGetListOfObjects<T> prepare() {
+            if (query != null) {
+                return new PreparedGetListOfObjects<T>(
+                        storIOSQLite,
+                        type,
+                        query,
+                        getResolver
+                );
+            } else if (rawQuery != null) {
+                return new PreparedGetListOfObjects<T>(
+                        storIOSQLite,
+                        type,
+                        rawQuery,
+                        getResolver
+                );
+            } else {
+                throw new IllegalStateException("Please specify Query or RawQuery");
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/DefaultPutResolver.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/DefaultPutResolver.java
new file mode 100644
index 0000000..3eeb788
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/DefaultPutResolver.java
@@ -0,0 +1,95 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.InsertQuery;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.UpdateQuery;
+
+import static com.pushtorefresh.storio.internal.Queries.nullableArrayOfStrings;
+import static com.pushtorefresh.storio.internal.Queries.nullableString;
+
+/**
+ * Default implementation of {@link PutResolver}.
+ * <p>
+ * Thread-safe.
+ *
+ * @param <T> type of objects to put.
+ */
+public abstract class DefaultPutResolver<T> extends PutResolver<T> {
+
+    /**
+     * Converts object of required type to {@link InsertQuery}.
+     *
+     * @param object non-null object that should be converted to {@link InsertQuery}.
+     * @return non-null {@link InsertQuery}.
+     */
+    @NonNull
+    protected abstract InsertQuery mapToInsertQuery(@NonNull T object);
+
+    /**
+     * Converts object of required type to {@link UpdateQuery}.
+     *
+     * @param object non-null object that should be converted to {@link UpdateQuery}.
+     * @return non-null {@link UpdateQuery}.
+     */
+    @NonNull
+    protected abstract UpdateQuery mapToUpdateQuery(@NonNull T object);
+
+    /**
+     * Converts object of required type to {@link ContentValues}.
+     *
+     * @param object non-null object that should be converted to {@link ContentValues}.
+     * @return non-null {@link ContentValues}.
+     */
+    @NonNull
+    protected abstract ContentValues mapToContentValues(@NonNull T object);
+
+    /**
+     * {@inheritDoc}
+     */
+    @NonNull
+    @Override
+    public PutResult performPut(@NonNull StorIOSQLite storIOSQLite, @NonNull T object) {
+        final UpdateQuery updateQuery = mapToUpdateQuery(object);
+
+        // for data consistency in concurrent environment, encapsulate Put Operation into transaction
+        storIOSQLite.internal().beginTransaction();
+
+        try {
+            final Cursor cursor = storIOSQLite.internal().query(Query.builder()
+                    .table(updateQuery.table())
+                    .where(nullableString(updateQuery.where()))
+                    .whereArgs((Object[]) nullableArrayOfStrings(updateQuery.whereArgs()))
+                    .build());
+
+            final PutResult putResult;
+
+            try {
+                final ContentValues contentValues = mapToContentValues(object);
+
+                if (cursor.getCount() == 0) {
+                    final InsertQuery insertQuery = mapToInsertQuery(object);
+                    final long insertedId = storIOSQLite.internal().insert(insertQuery, contentValues);
+                    putResult = PutResult.newInsertResult(insertedId, insertQuery.table());
+                } else {
+                    final int numberOfRowsUpdated = storIOSQLite.internal().update(updateQuery, contentValues);
+                    putResult = PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table());
+                }
+            } finally {
+                cursor.close();
+            }
+
+            // everything okay
+            storIOSQLite.internal().setTransactionSuccessful();
+
+            return putResult;
+        } finally {
+            // in case of bad situations, db won't be affected
+            storIOSQLite.internal().endTransaction();
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPut.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPut.java
new file mode 100644
index 0000000..12b114c
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPut.java
@@ -0,0 +1,94 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.content.ContentValues;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.operations.PreparedOperation;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * Prepared Put Operation for {@link StorIOSQLite} which performs insert or update data
+ * in {@link StorIOSQLite}.
+ */
+public abstract class PreparedPut<Result> implements PreparedOperation<Result> {
+
+    @NonNull
+    protected final StorIOSQLite storIOSQLite;
+
+    PreparedPut(@NonNull StorIOSQLite storIOSQLite) {
+        this.storIOSQLite = storIOSQLite;
+    }
+
+    /**
+     * Builder for {@link PreparedPut}.
+     */
+    public static final class Builder {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        public Builder(@NonNull StorIOSQLite storIOSQLite) {
+            this.storIOSQLite = storIOSQLite;
+        }
+
+        /**
+         * Prepares Put Operation for one instance of {@link ContentValues}.
+         *
+         * @param contentValues content values to put.
+         * @return builder.
+         */
+        @NonNull
+        public PreparedPutContentValues.Builder contentValues(@NonNull ContentValues contentValues) {
+            return new PreparedPutContentValues.Builder(storIOSQLite, contentValues);
+        }
+
+        /**
+         * Prepares Put Operation for multiple {@link ContentValues}.
+         *
+         * @param contentValuesIterable content values to put.
+         * @return builder.
+         */
+        @NonNull
+        public PreparedPutContentValuesIterable.Builder contentValues(@NonNull Iterable<ContentValues> contentValuesIterable) {
+            return new PreparedPutContentValuesIterable.Builder(storIOSQLite, contentValuesIterable);
+        }
+
+        /**
+         * Prepares Put Operation for multiple {@link ContentValues}.
+         *
+         * @param contentValuesArray content values to put.
+         * @return builder.
+         */
+        @NonNull
+        public PreparedPutContentValuesIterable.Builder contentValues(@NonNull ContentValues... contentValuesArray) {
+            return new PreparedPutContentValuesIterable.Builder(storIOSQLite, Arrays.asList(contentValuesArray));
+        }
+
+        /**
+         * Prepares Put Operation for one object.
+         *
+         * @param object object to put.
+         * @param <T>    type of object.
+         * @return builder.
+         */
+        @NonNull
+        public <T> PreparedPutObject.Builder<T> object(T object) {
+            return new PreparedPutObject.Builder<T>(storIOSQLite, object);
+        }
+
+        /**
+         * Prepares Put Operation for multiple objects.
+         *
+         * @param objects objects to put.
+         * @param <T>     type of objects.
+         * @return builder.
+         */
+        @NonNull
+        public <T> PreparedPutCollectionOfObjects.Builder<T> objects(@NonNull Collection<T> objects) {
+            return new PreparedPutCollectionOfObjects.Builder<T>(storIOSQLite, objects);
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutCollectionOfObjects.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutCollectionOfObjects.java
new file mode 100644
index 0000000..bbe65f6
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutCollectionOfObjects.java
@@ -0,0 +1,236 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+import com.pushtorefresh.storio.sqlite.Changes;
+import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+public final class PreparedPutCollectionOfObjects<T> extends PreparedPut<PutResults<T>> {
+
+    @NonNull
+    private final Collection<T> objects;
+
+    private final boolean useTransaction;
+
+    @Nullable
+    private final PutResolver<T> explicitPutResolver;
+
+    PreparedPutCollectionOfObjects(@NonNull StorIOSQLite storIOSQLite,
+                                   @NonNull Collection<T> objects,
+                                   @Nullable PutResolver<T> explicitPutResolver,
+                                   boolean useTransaction) {
+        super(storIOSQLite);
+        this.objects = objects;
+        this.useTransaction = useTransaction;
+        this.explicitPutResolver = explicitPutResolver;
+    }
+
+    /**
+     * Executes Put Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null results of Put Operation.
+     */
+    @SuppressWarnings("unchecked")
+    @WorkerThread
+    @NonNull
+    @Override
+    public PutResults<T> executeAsBlocking() {
+        final StorIOSQLite.Internal internal = storIOSQLite.internal();
+
+        // Nullable
+        final List<SimpleImmutableEntry<T, PutResolver<T>>> objectsAndPutResolvers;
+
+        if (explicitPutResolver != null) {
+            objectsAndPutResolvers = null;
+        } else {
+            objectsAndPutResolvers = new ArrayList<SimpleImmutableEntry<T, PutResolver<T>>>(objects.size());
+
+            for (final T object : objects) {
+                final SQLiteTypeMapping<T> typeMapping
+                        = (SQLiteTypeMapping<T>) internal.typeMapping(object.getClass());
+
+                if (typeMapping == null) {
+                    throw new IllegalStateException("One of the objects from the collection does not have type mapping: " +
+                            "object = " + object + ", object.class = " + object.getClass() + "," +
+                            "db was not affected by this operation, please add type mapping for this type");
+                }
+
+                objectsAndPutResolvers.add(new SimpleImmutableEntry<T, PutResolver<T>>(
+                        object,
+                        typeMapping.putResolver()
+                ));
+            }
+        }
+
+        if (useTransaction) {
+            internal.beginTransaction();
+        }
+
+        final Map<T, PutResult> results = new HashMap<T, PutResult>(objects.size());
+        boolean transactionSuccessful = false;
+
+        try {
+            if (explicitPutResolver != null) {
+                for (final T object : objects) {
+                    final PutResult putResult = explicitPutResolver.performPut(storIOSQLite, object);
+                    results.put(object, putResult);
+
+                    if (!useTransaction) {
+                        internal.notifyAboutChanges(Changes.newInstance(putResult.affectedTables()));
+                    }
+                }
+            } else {
+                for (final SimpleImmutableEntry<T, PutResolver<T>> objectAndPutResolver : objectsAndPutResolvers) {
+                    final T object = objectAndPutResolver.getKey();
+                    final PutResolver<T> putResolver = objectAndPutResolver.getValue();
+
+                    final PutResult putResult = putResolver.performPut(storIOSQLite, object);
+
+                    results.put(object, putResult);
+
+                    if (!useTransaction) {
+                        internal.notifyAboutChanges(Changes.newInstance(putResult.affectedTables()));
+                    }
+                }
+            }
+
+            if (useTransaction) {
+                internal.setTransactionSuccessful();
+                transactionSuccessful = true;
+            }
+        } finally {
+            if (useTransaction) {
+                internal.endTransaction();
+
+                // if delete was in transaction and it was successful -> notify about changes
+                if (transactionSuccessful) {
+                    final Set<String> affectedTables = new HashSet<String>(1); // in most cases it will be 1 table
+
+                    for (final T object : results.keySet()) {
+                        affectedTables.addAll(results.get(object).affectedTables());
+                    }
+
+                    // IMPORTANT: Notifying about change should be done after end of transaction
+                    // It'll reduce number of possible deadlock situations
+                    internal.notifyAboutChanges(Changes.newInstance(affectedTables));
+                }
+            }
+        }
+
+        return PutResults.newInstance(results);
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Put Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * put only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Put Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<PutResults<T>> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedPutCollectionOfObjects}
+     *
+     * @param <T> type of objects to put
+     */
+    public static final class Builder<T> {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        @NonNull
+        private final Collection<T> objects;
+
+        private PutResolver<T> putResolver;
+
+        private boolean useTransaction = true;
+
+        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull Collection<T> objects) {
+            this.storIOSQLite = storIOSQLite;
+            this.objects = objects;
+        }
+
+        /**
+         * Optional: Specifies {@link PutResolver} for Put Operation
+         * which allows you to customize behavior of Put Operation
+         * <p/>
+         * Can be set via {@link SQLiteTypeMapping}
+         * If it's not set via {@link SQLiteTypeMapping} or explicitly -> exception will be thrown
+         *
+         * @param putResolver put resolver
+         * @return builder
+         * @see DefaultPutResolver
+         */
+        @NonNull
+        public Builder<T> withPutResolver(@NonNull PutResolver<T> putResolver) {
+            this.putResolver = putResolver;
+            return this;
+        }
+
+        /**
+         * Optional: Defines that Put Operation will use transaction if it is supported by implementation of {@link StorIOSQLite}
+         * <p/>
+         * By default, transaction will be used
+         *
+         * @return builder
+         */
+        @NonNull
+        public Builder<T> useTransaction(boolean useTransaction) {
+            this.useTransaction = useTransaction;
+            return this;
+        }
+
+        /**
+         * Prepares Put Operation
+         *
+         * @return {@link PreparedPutCollectionOfObjects} instance
+         */
+        @NonNull
+        public PreparedPutCollectionOfObjects<T> prepare() {
+            return new PreparedPutCollectionOfObjects<T>(
+                    storIOSQLite,
+                    objects,
+                    putResolver,
+                    useTransaction
+            );
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValues.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValues.java
new file mode 100644
index 0000000..8e2172a
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValues.java
@@ -0,0 +1,146 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.content.ContentValues;
+import android.support.annotation.NonNull;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+import com.pushtorefresh.storio.sqlite.Changes;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Put Operation for {@link StorIOSQLite}.
+ */
+public final class PreparedPutContentValues extends PreparedPut<PutResult> {
+
+    @NonNull
+    private final ContentValues contentValues;
+
+    @NonNull
+    private final PutResolver<ContentValues> putResolver;
+
+    PreparedPutContentValues(@NonNull StorIOSQLite storIOSQLite, @NonNull ContentValues contentValues, @NonNull PutResolver<ContentValues> putResolver) {
+        super(storIOSQLite);
+        this.contentValues = contentValues;
+        this.putResolver = putResolver;
+    }
+
+    /**
+     * Executes Put Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null result of Put Operation.
+     */
+    @WorkerThread
+    @NonNull
+    @Override
+    public PutResult executeAsBlocking() {
+        final PutResult putResult = putResolver.performPut(storIOSQLite, contentValues);
+        storIOSQLite.internal().notifyAboutChanges(Changes.newInstance(putResult.affectedTables()));
+        return putResult;
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Put Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * put only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Put Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<PutResult> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedPutContentValues}.
+     */
+    public static final class Builder {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        @NonNull
+        private final ContentValues contentValues;
+
+        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull ContentValues contentValues) {
+            this.storIOSQLite = storIOSQLite;
+            this.contentValues = contentValues;
+        }
+
+        /**
+         * Required: Specifies {@link PutResolver} for Put Operation
+         * which allows you to customize behavior of Put Operation.
+         *
+         * @param putResolver put resolver.
+         * @return builder.
+         * @see DefaultPutResolver
+         */
+        @NonNull
+        public CompleteBuilder withPutResolver(@NonNull PutResolver<ContentValues> putResolver) {
+            checkNotNull(putResolver, "Please specify put resolver");
+
+            return new CompleteBuilder(
+                    storIOSQLite,
+                    contentValues,
+                    putResolver
+            );
+        }
+    }
+
+    /**
+     * Compile-time safe part of {@link Builder}.
+     */
+    public static final class CompleteBuilder {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        @NonNull
+        private final ContentValues contentValues;
+
+        @NonNull
+        private final PutResolver<ContentValues> putResolver;
+
+        CompleteBuilder(@NonNull StorIOSQLite storIOSQLite, @NonNull ContentValues contentValues, @NonNull PutResolver<ContentValues> putResolver) {
+            this.storIOSQLite = storIOSQLite;
+            this.contentValues = contentValues;
+            this.putResolver = putResolver;
+        }
+
+        /**
+         * Prepares Put Operation.
+         *
+         * @return {@link PreparedPutContentValues} instance.
+         */
+        @NonNull
+        public PreparedPutContentValues prepare() {
+            return new PreparedPutContentValues(
+                    storIOSQLite,
+                    contentValues,
+                    putResolver
+            );
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValuesIterable.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValuesIterable.java
new file mode 100644
index 0000000..efe3df8
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValuesIterable.java
@@ -0,0 +1,211 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.content.ContentValues;
+import android.support.annotation.NonNull;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+import com.pushtorefresh.storio.sqlite.Changes;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+public final class PreparedPutContentValuesIterable extends PreparedPut<PutResults<ContentValues>> {
+
+    @NonNull
+    private final Iterable<ContentValues> contentValuesIterable;
+
+    @NonNull
+    private final PutResolver<ContentValues> putResolver;
+
+    private final boolean useTransaction;
+
+    PreparedPutContentValuesIterable(
+            @NonNull StorIOSQLite storIOSQLite,
+            @NonNull Iterable<ContentValues> contentValuesIterable,
+            @NonNull PutResolver<ContentValues> putResolver,
+            boolean useTransaction) {
+
+        super(storIOSQLite);
+        this.contentValuesIterable = contentValuesIterable;
+        this.putResolver = putResolver;
+        this.useTransaction = useTransaction;
+    }
+
+    /**
+     * Executes Put Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null results of Put Operation.
+     */
+    @WorkerThread
+    @NonNull
+    @Override
+    public PutResults<ContentValues> executeAsBlocking() {
+        final StorIOSQLite.Internal internal = storIOSQLite.internal();
+
+        final Map<ContentValues, PutResult> putResults = new HashMap<ContentValues, PutResult>();
+
+        if (useTransaction) {
+            internal.beginTransaction();
+        }
+
+        boolean transactionSuccessful = false;
+
+        try {
+            for (ContentValues contentValues : contentValuesIterable) {
+                final PutResult putResult = putResolver.performPut(storIOSQLite, contentValues);
+                putResults.put(contentValues, putResult);
+
+                if (!useTransaction) {
+                    internal.notifyAboutChanges(Changes.newInstance(putResult.affectedTables()));
+                }
+            }
+
+            if (useTransaction) {
+                storIOSQLite.internal().setTransactionSuccessful();
+                transactionSuccessful = true;
+            }
+        } finally {
+            if (useTransaction) {
+                storIOSQLite.internal().endTransaction();
+
+                if (transactionSuccessful) {
+                    final Set<String> affectedTables = new HashSet<String>(1); // in most cases it will be 1 table
+
+                    for (final ContentValues contentValues : putResults.keySet()) {
+                        affectedTables.addAll(putResults.get(contentValues).affectedTables());
+                    }
+
+                    storIOSQLite.internal().notifyAboutChanges(Changes.newInstance(affectedTables));
+                }
+            }
+        }
+
+        return PutResults.newInstance(putResults);
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Put Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * put only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Put Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<PutResults<ContentValues>> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedPutContentValuesIterable}
+     */
+    public static final class Builder {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        @NonNull
+        private final Iterable<ContentValues> contentValuesIterable;
+
+        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull Iterable<ContentValues> contentValuesIterable) {
+            this.storIOSQLite = storIOSQLite;
+            this.contentValuesIterable = contentValuesIterable;
+        }
+
+        /**
+         * Required: Specifies {@link PutResolver} for Put Operation
+         * which allows you to customize behavior of Put Operation
+         *
+         * @param putResolver put resolver
+         * @return builder
+         * @see DefaultPutResolver
+         */
+        @NonNull
+        public CompleteBuilder withPutResolver(@NonNull PutResolver<ContentValues> putResolver) {
+            checkNotNull(putResolver, "Please specify put resolver");
+
+            return new CompleteBuilder(
+                    storIOSQLite,
+                    contentValuesIterable,
+                    putResolver
+            );
+        }
+    }
+
+    /**
+     * Compile-time safe part of {@link Builder}
+     */
+    public static final class CompleteBuilder {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        @NonNull
+        private final Iterable<ContentValues> contentValuesIterable;
+
+        @NonNull
+        private final PutResolver<ContentValues> putResolver;
+
+        private boolean useTransaction = true;
+
+        CompleteBuilder(@NonNull StorIOSQLite storIOSQLite, @NonNull Iterable<ContentValues> contentValuesIterable, @NonNull PutResolver<ContentValues> putResolver) {
+            this.storIOSQLite = storIOSQLite;
+            this.contentValuesIterable = contentValuesIterable;
+            this.putResolver = putResolver;
+        }
+
+        /**
+         * Optional: Defines that Put Operation will use transaction
+         * if it is supported by implementation of {@link StorIOSQLite}
+         * <p/>
+         * By default, transaction will be used
+         *
+         * @return builder
+         */
+        @NonNull
+        public CompleteBuilder useTransaction(boolean useTransaction) {
+            this.useTransaction = useTransaction;
+            return this;
+        }
+
+        /**
+         * Prepares Put Operation
+         *
+         * @return {@link PreparedPutContentValuesIterable} instance
+         */
+        @NonNull
+        public PreparedPutContentValuesIterable prepare() {
+            return new PreparedPutContentValuesIterable(
+                    storIOSQLite,
+                    contentValuesIterable,
+                    putResolver,
+                    useTransaction
+            );
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutObject.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutObject.java
new file mode 100644
index 0000000..e90d90e
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutObject.java
@@ -0,0 +1,150 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import com.pushtorefresh.storio.operations.internal.OnSubscribeExecuteAsBlocking;
+import com.pushtorefresh.storio.sqlite.Changes;
+import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+
+import rx.Observable;
+import rx.schedulers.Schedulers;
+
+import static com.pushtorefresh.storio.internal.Environment.throwExceptionIfRxJavaIsNotAvailable;
+
+/**
+ * Prepared Put Operation for {@link StorIOSQLite}.
+ *
+ * @param <T> type of object to put.
+ */
+public final class PreparedPutObject<T> extends PreparedPut<PutResult> {
+
+    @NonNull
+    private final T object;
+
+    @Nullable
+    private final PutResolver<T> explicitPutResolver;
+
+    PreparedPutObject(@NonNull StorIOSQLite storIOSQLite,
+                      @NonNull T object,
+                      @Nullable PutResolver<T> explicitPutResolver) {
+        super(storIOSQLite);
+        this.object = object;
+        this.explicitPutResolver = explicitPutResolver;
+    }
+
+    /**
+     * Executes Put Operation immediately in current thread.
+     * <p/>
+     * Notice: This is blocking I/O operation that should not be executed on the Main Thread,
+     * it can cause ANR (Activity Not Responding dialog), block the UI and drop animations frames.
+     * So please, call this method on some background thread. See {@link WorkerThread}.
+     *
+     * @return non-null result of Put Operation.
+     */
+    @SuppressWarnings("unchecked")
+    @WorkerThread
+    @NonNull
+    @Override
+    public PutResult executeAsBlocking() {
+        final StorIOSQLite.Internal internal = storIOSQLite.internal();
+
+        final PutResolver<T> putResolver;
+
+        if (explicitPutResolver != null) {
+            putResolver = explicitPutResolver;
+        } else {
+            final SQLiteTypeMapping<T> typeMapping = internal.typeMapping((Class<T>) object.getClass());
+
+            if (typeMapping == null) {
+                throw new IllegalStateException("Object does not have type mapping: " +
+                        "object = " + object + ", object.class = " + object.getClass() + "," +
+                        "db was not affected by this operation, please add type mapping for this type");
+            }
+
+            putResolver = typeMapping.putResolver();
+        }
+
+        final PutResult putResult = putResolver.performPut(storIOSQLite, object);
+        internal.notifyAboutChanges(Changes.newInstance(putResult.affectedTables()));
+        return putResult;
+    }
+
+    /**
+     * Creates {@link Observable} which will perform Put Operation and send result to observer.
+     * <p/>
+     * Returned {@link Observable} will be "Cold Observable", which means that it performs
+     * put only after subscribing to it. Also, it emits the result once.
+     * <p/>
+     * <dl>
+     * <dt><b>Scheduler:</b></dt>
+     * <dd>Operates on {@link Schedulers#io()}.</dd>
+     * </dl>
+     *
+     * @return non-null {@link Observable} which will perform Put Operation.
+     * and send result to observer.
+     */
+    @NonNull
+    @Override
+    public Observable<PutResult> createObservable() {
+        throwExceptionIfRxJavaIsNotAvailable("createObservable()");
+
+        return Observable
+                .create(OnSubscribeExecuteAsBlocking.newInstance(this))
+                .subscribeOn(Schedulers.io());
+    }
+
+    /**
+     * Builder for {@link PreparedPutObject}.
+     *
+     * @param <T> type of object to put.
+     */
+    public static final class Builder<T> {
+
+        @NonNull
+        private final StorIOSQLite storIOSQLite;
+
+        @NonNull
+        private final T object;
+
+        private PutResolver<T> putResolver;
+
+        Builder(@NonNull StorIOSQLite storIOSQLite, @NonNull T object) {
+            this.storIOSQLite = storIOSQLite;
+            this.object = object;
+        }
+
+        /**
+         * Optional: Specifies {@link PutResolver} for Put Operation
+         * which allows you to customize behavior of Put Operation.
+         * <p/>
+         * Can be set via {@link SQLiteTypeMapping}
+         * If it's not set via {@link SQLiteTypeMapping} or explicitly -> exception will be thrown.
+         *
+         * @param putResolver put resolver.
+         * @return builder.
+         * @see DefaultPutResolver
+         */
+        @NonNull
+        public Builder<T> withPutResolver(@NonNull PutResolver<T> putResolver) {
+            this.putResolver = putResolver;
+            return this;
+        }
+
+        /**
+         * Prepares Put Operation.
+         *
+         * @return {@link PreparedPutObject} instance.
+         */
+        @NonNull
+        public PreparedPutObject<T> prepare() {
+            return new PreparedPutObject<T>(
+                    storIOSQLite,
+                    object,
+                    putResolver
+            );
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PutResolver.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PutResolver.java
new file mode 100644
index 0000000..d8c1572
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PutResolver.java
@@ -0,0 +1,24 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+
+/**
+ * Defines behavior of Put Operation (insert or update).
+ *
+ * @param <T> type of objects to put.
+ * @see DefaultPutResolver
+ */
+public abstract class PutResolver<T> {
+
+    /**
+     * Performs put of an object.
+     *
+     * @param storIOSQLite {@link StorIOSQLite} instance to perform put into.
+     * @param object       non-null object that should be put into {@link StorIOSQLite}.
+     * @return non-null result of Put Operation.
+     */
+    @NonNull
+    public abstract PutResult performPut(@NonNull StorIOSQLite storIOSQLite, @NonNull T object);
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PutResult.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PutResult.java
new file mode 100644
index 0000000..450329c
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PutResult.java
@@ -0,0 +1,182 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.Set;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotNull;
+
+/**
+ * Immutable container for result of Put Operation.
+ * <p>
+ * Instances of this class are immutable.
+ */
+public class PutResult {
+
+    @Nullable
+    private final Long insertedId;
+
+    @Nullable
+    private final Integer numberOfRowsUpdated;
+
+    @NonNull
+    private final Set<String> affectedTables;
+
+    private PutResult(@Nullable Long insertedId, @Nullable Integer numberOfRowsUpdated, @NonNull Set<String> affectedTables) {
+        checkNotNull(affectedTables, "Please specify affected tables");
+        this.insertedId = insertedId;
+        this.numberOfRowsUpdated = numberOfRowsUpdated;
+        this.affectedTables = Collections.unmodifiableSet(affectedTables);
+    }
+
+    /**
+     * Creates {@link PutResult} of insert.
+     *
+     * @param insertedId     id of new row.
+     * @param affectedTables tables that were affected.
+     * @return new {@link PutResult} instance.
+     */
+    @NonNull
+    public static PutResult newInsertResult(long insertedId, @NonNull Set<String> affectedTables) {
+        return new PutResult(insertedId, null, affectedTables);
+    }
+
+    /**
+     * Creates {@link PutResult} of insert.
+     *
+     * @param insertedId    id of new row.
+     * @param affectedTable table that was affected.
+     * @return new {@link PutResult} instance.
+     */
+    @NonNull
+    public static PutResult newInsertResult(long insertedId, @NonNull String affectedTable) {
+        return new PutResult(insertedId, null, Collections.singleton(affectedTable));
+    }
+
+    /**
+     * Creates {@link PutResult} of update.
+     *
+     * @param numberOfRowsUpdated number of rows that were updated.
+     * @param affectedTables      tables that were affected.
+     * @return new {@link PutResult} instance.
+     */
+    @NonNull
+    public static PutResult newUpdateResult(int numberOfRowsUpdated, @NonNull Set<String> affectedTables) {
+        return new PutResult(null, numberOfRowsUpdated, affectedTables);
+    }
+
+    /**
+     * Creates {@link PutResult} of update.
+     *
+     * @param numberOfRowsUpdated number of rows that were updated.
+     * @param affectedTable       table that was affected.
+     * @return new {@link PutResult} instance.
+     */
+    @NonNull
+    public static PutResult newUpdateResult(int numberOfRowsUpdated, @NonNull String affectedTable) {
+        return new PutResult(null, numberOfRowsUpdated, Collections.singleton(affectedTable));
+    }
+
+    /**
+     * Checks whether result of Put Operation was "insert".
+     *
+     * @return {@code true} if something was inserted into
+     * {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}, {@code false} otherwise.
+     */
+    public boolean wasInserted() {
+        return insertedId != null;
+    }
+
+    /**
+     * Checks whether result of Put Operation was NOT "insert".
+     *
+     * @return {@code true} if nothing was inserted into
+     * {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}, {@code false} if something was inserted.
+     */
+    public boolean wasNotInserted() {
+        return !wasInserted();
+    }
+
+    /**
+     * Checks whether result of Put Operation was "update".
+     *
+     * @return {@code true} if something was updated in
+     * {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}, {@code false} otherwise.
+     */
+    public boolean wasUpdated() {
+        return numberOfRowsUpdated != null;
+    }
+
+    /**
+     * Checks whether result of Put Operation was NOT "update".
+     *
+     * @return {@code true} if nothing was updated in
+     * {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}, {@code false} if something was updated.
+     */
+    public boolean wasNotUpdated() {
+        return !wasUpdated();
+    }
+
+    /**
+     * Gets id of inserted row.
+     *
+     * @return {@code null} if nothing was inserted or id of inserted row.
+     */
+    @Nullable
+    public Long insertedId() {
+        return insertedId;
+    }
+
+    /**
+     * Gets number of rows updated.
+     *
+     * @return {@code null} if nothing was updated or number of updated rows.
+     */
+    @Nullable
+    public Integer numberOfRowsUpdated() {
+        return numberOfRowsUpdated;
+    }
+
+    /**
+     * Gets names of affected tables.
+     *
+     * @return non-null unmodifiable set of affected tables.
+     */
+    @NonNull
+    public Set<String> affectedTables() {
+        return affectedTables;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        PutResult putResult = (PutResult) o;
+
+        if (insertedId != null ? !insertedId.equals(putResult.insertedId) : putResult.insertedId != null)
+            return false;
+        if (numberOfRowsUpdated != null ? !numberOfRowsUpdated.equals(putResult.numberOfRowsUpdated) : putResult.numberOfRowsUpdated != null)
+            return false;
+        return affectedTables.equals(putResult.affectedTables);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = insertedId != null ? insertedId.hashCode() : 0;
+        result = 31 * result + (numberOfRowsUpdated != null ? numberOfRowsUpdated.hashCode() : 0);
+        result = 31 * result + affectedTables.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "PutResult{" +
+                "insertedId=" + insertedId +
+                ", numberOfRowsUpdated=" + numberOfRowsUpdated +
+                ", affectedTables=" + affectedTables +
+                '}';
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PutResults.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PutResults.java
new file mode 100644
index 0000000..4030701
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/operations/put/PutResults.java
@@ -0,0 +1,127 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Immutable container for results of Put Operation.
+ * <p>
+ * Instances of this class are Immutable
+ *
+ * @param <T> type of objects that were put.
+ */
+public final class PutResults<T> {
+
+    @NonNull
+    private final Map<T, PutResult> results;
+
+    @Nullable
+    private volatile Integer numberOfInsertsCache;
+
+    @Nullable
+    private volatile Integer numberOfUpdatesCache;
+
+    private PutResults(@NonNull Map<T, PutResult> putResults) {
+        this.results = Collections.unmodifiableMap(putResults);
+    }
+
+    /**
+     * Creates new instance of {@link PutResults}.
+     *
+     * @param putResults results of Put Operation.
+     * @param <T>        type of objects.
+     * @return immutable instance of {@link PutResults}.
+     */
+    @NonNull
+    public static <T> PutResults<T> newInstance(@NonNull Map<T, PutResult> putResults) {
+        return new PutResults<T>(putResults);
+    }
+
+    /**
+     * Returns immutable Map of pairs {@code (object, PutResult)}.
+     *
+     * @return immutable Map of pairs {@code (object, PutResult)}.
+     */
+    @NonNull
+    public Map<T, PutResult> results() {
+        return results;
+    }
+
+    /**
+     * Returns number of inserts from all {@link #results()}.
+     *
+     * @return number of inserts from all {@link #results()}.
+     */
+    public int numberOfInserts() {
+        final Integer cachedValue = numberOfInsertsCache;
+
+        if (cachedValue != null) {
+            return cachedValue;
+        }
+
+        int numberOfInserts = 0;
+
+        for (T object : results.keySet()) {
+            if (results.get(object).wasInserted()) {
+                numberOfInserts++;
+            }
+        }
+
+        numberOfInsertsCache = numberOfInserts;
+
+        return numberOfInserts;
+    }
+
+    /**
+     * Returns number of updates from all {@link #results()}.
+     *
+     * @return number of updates from all {@link #results()}.
+     */
+    @SuppressWarnings("ConstantConditions")
+    public int numberOfUpdates() {
+        final Integer cachedValue = numberOfUpdatesCache;
+
+        if (cachedValue != null) {
+            return cachedValue;
+        }
+
+        int numberOfUpdates = 0;
+
+        for (T object : results.keySet()) {
+            final PutResult putResult = results.get(object);
+
+            if (putResult.wasUpdated()) {
+                numberOfUpdates += putResult.numberOfRowsUpdated();
+            }
+        }
+
+        numberOfUpdatesCache = numberOfUpdates;
+
+        return numberOfUpdates;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        PutResults<?> that = (PutResults<?>) o;
+
+        return results.equals(that.results);
+    }
+
+    @Override
+    public int hashCode() {
+        return results.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return "PutResults{" +
+                "results=" + results +
+                '}';
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/DeleteQuery.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/DeleteQuery.java
new file mode 100644
index 0000000..2afaf3d
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/DeleteQuery.java
@@ -0,0 +1,211 @@
+package com.pushtorefresh.storio.sqlite.queries;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.List;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotEmpty;
+import static com.pushtorefresh.storio.internal.Queries.nonNullString;
+import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullListOfStrings;
+
+/**
+ * Delete query for {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}.
+ * <p>
+ * Instances of this class are immutable.
+ */
+public final class DeleteQuery {
+
+    @NonNull
+    private final String table;
+
+    @NonNull
+    private final String where;
+
+    @NonNull
+    private final List<String> whereArgs;
+
+    /**
+     * Please use {@link com.pushtorefresh.storio.sqlite.queries.DeleteQuery.Builder}
+     * instead of constructor.
+     */
+    private DeleteQuery(@NonNull String table, @Nullable String where, @Nullable List<String> whereArgs) {
+        this.table = table;
+        this.where = nonNullString(where);
+        this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
+    }
+
+    /**
+     * Gets table name.
+     *
+     * @return non-null table name.
+     */
+    @NonNull
+    public String table() {
+        return table;
+    }
+
+    /**
+     * Gets {@code WHERE} clause.
+     * <p>
+     * Optional filter declaring which rows to return.
+     * <p>
+     * Formatted as an SQL {@code WHERE} clause (excluding the {@code WHERE} itself).
+     * <p>
+     * If empty — Query will delete all rows for the given table.
+     *
+     * @return non-null {@code WHERE} clause.
+     */
+    @NonNull
+    public String where() {
+        return where;
+    }
+
+    /**
+     * Gets optional immutable list of arguments for {@link #where()} clause.
+     *
+     * @return non-null, immutable list of arguments for {@code WHERE} clause.
+     */
+    @NonNull
+    public List<String> whereArgs() {
+        return whereArgs;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        DeleteQuery that = (DeleteQuery) o;
+
+        if (!table.equals(that.table)) return false;
+        if (!where.equals(that.where)) return false;
+        return whereArgs.equals(that.whereArgs);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = table.hashCode();
+        result = 31 * result + where.hashCode();
+        result = 31 * result + whereArgs.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "DeleteQuery{" +
+                "table='" + table + '\'' +
+                ", where='" + where + '\'' +
+                ", whereArgs=" + whereArgs +
+                '}';
+    }
+
+    /**
+     * Creates new builder for {@link DeleteQuery}.
+     *
+     * @return non-null instance of {@link DeleteQuery.Builder}.
+     */
+    @NonNull
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link DeleteQuery}.
+     */
+    public static final class Builder {
+
+        /**
+         * Please use {@link DeleteQuery#builder()} instead of this.
+         */
+        Builder() {
+        }
+
+        /**
+         * Required: Specifies table name.
+         *
+         * @param table non-null and not empty table name.
+         * @return builder.
+         * @see DeleteQuery#table()
+         */
+        @NonNull
+        public CompleteBuilder table(@NonNull String table) {
+            checkNotEmpty(table, "Table name is null or empty");
+            return new CompleteBuilder(table);
+        }
+    }
+
+    /**
+     * Compile-time safe part of builder for {@link DeleteQuery}.
+     */
+    public static final class CompleteBuilder {
+
+        @NonNull
+        private final String table;
+
+        private String where;
+
+        private List<String> whereArgs;
+
+        CompleteBuilder(@NonNull String table) {
+            this.table = table;
+        }
+
+        /**
+         * Optional: Specifies {@code WHERE} clause.
+         * <p>
+         * Optional filter declaring which rows to return.
+         * <p>
+         * Formatted as an SQL WHERE clause (excluding the WHERE itself).
+         * <p>
+         * Passing null will DELETE all rows for the given table.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param where {@code WHERE} clause.
+         * @return builder.
+         * @see DeleteQuery#where()
+         */
+        @NonNull
+        public CompleteBuilder where(@Nullable String where) {
+            this.where = where;
+            return this;
+        }
+
+        /**
+         * Optional: Specifies arguments for {@code WHERE} clause.
+         * <p>
+         * Passed objects will be immediately converted
+         * to list of {@link String} via calling {@link Object#toString()}.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param whereArgs list of arguments for {@code WHERE} clause.
+         * @return builder.
+         * @see DeleteQuery#whereArgs()
+         */
+        @NonNull
+        public CompleteBuilder whereArgs(@Nullable Object... whereArgs) {
+            this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
+            return this;
+        }
+
+        /**
+         * Builds immutable instance of {@link DeleteQuery}.
+         *
+         * @return immutable instance of {@link DeleteQuery}.
+         */
+        @NonNull
+        public DeleteQuery build() {
+            if (where == null && whereArgs != null && !whereArgs.isEmpty()) {
+                throw new IllegalStateException("You can not use whereArgs without where clause");
+            }
+
+            return new DeleteQuery(
+                    table,
+                    where,
+                    whereArgs
+            );
+        }
+    }
+}
\ No newline at end of file
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/InsertQuery.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/InsertQuery.java
new file mode 100644
index 0000000..2ee5266
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/InsertQuery.java
@@ -0,0 +1,169 @@
+package com.pushtorefresh.storio.sqlite.queries;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotEmpty;
+
+/**
+ * Insert query for {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}.
+ * <p/>
+ * Instances of this class are immutable.
+ */
+public final class InsertQuery {
+
+    @NonNull
+    private final String table;
+
+    @Nullable
+    private final String nullColumnHack;
+
+    /**
+     * Please use {@link com.pushtorefresh.storio.sqlite.queries.InsertQuery.Builder}
+     * instead of constructor.
+     */
+    private InsertQuery(@NonNull String table, @Nullable String nullColumnHack) {
+        this.table = table;
+        this.nullColumnHack = nullColumnHack;
+    }
+
+    /**
+     * Gets table name.
+     *
+     * @return non-null table name.
+     */
+    @NonNull
+    public String table() {
+        return table;
+    }
+
+    /**
+     * Gets tricky-wiki hack for {@code null} columns in
+     * {@link android.database.sqlite.SQLiteDatabase}.
+     * <p/>
+     * SQL doesn't allow inserting a completely empty row
+     * without naming at least one column name. If your provided values
+     * are empty, no column names are known and an empty row can't be
+     * inserted. If not set to {@code null}, the {@code nullColumnHack}
+     * parameter provides the name of nullable column name to explicitly
+     * insert a {@code NULL} into in the case where your values is empty.
+     *
+     * @return nullable hack for {@code NULL} columns.
+     */
+    @Nullable
+    public String nullColumnHack() {
+        return nullColumnHack;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        InsertQuery that = (InsertQuery) o;
+
+        if (nullColumnHack != null ? !nullColumnHack.equals(that.nullColumnHack) : that.nullColumnHack != null)
+            return false;
+        if (!table.equals(that.table)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = table.hashCode();
+        result = 31 * result + (nullColumnHack != null ? nullColumnHack.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "InsertQuery{" +
+                "table='" + table + '\'' +
+                ", nullColumnHack='" + nullColumnHack + '\'' +
+                '}';
+    }
+
+    /**
+     * Creates new builder for {@link InsertQuery}.
+     *
+     * @return non-null instance of {@link InsertQuery.Builder}.
+     */
+    @NonNull
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link InsertQuery}.
+     */
+    public static final class Builder {
+
+        /**
+         * Please use {@link InsertQuery#builder()} instead of this.
+         */
+        Builder() {
+        }
+
+        /**
+         * Required: Specifies table name.
+         *
+         * @param table non-null and not empty table name.
+         * @return builder.
+         * @see InsertQuery#table()
+         */
+        @NonNull
+        public CompleteBuilder table(@NonNull String table) {
+            checkNotEmpty(table, "Table name is null or empty");
+            return new CompleteBuilder(table);
+        }
+    }
+
+    /**
+     * Compile-time safe part of builder for {@link DeleteQuery}.
+     */
+    public static final class CompleteBuilder {
+
+        @NonNull
+        private final String table;
+
+        private String nullColumnHack;
+
+        CompleteBuilder(@NonNull String table) {
+            this.table = table;
+        }
+
+        /**
+         * Optional: Specifies {@code NULL} column hack.
+         * <p/>
+         * SQL doesn't allow inserting a completely empty row without naming at least one column name.
+         * If your provided values are empty, no column names are known and an empty row can't be inserted.
+         * If not set to null, the nullColumnHack parameter provides the name of nullable column name
+         * to explicitly insert a NULL into in the case where your values is empty.
+         * <p/>
+         * Default value is {@code null}.
+         *
+         * @param nullColumnHack optional null column hack.
+         * @return builder.
+         * @see InsertQuery#nullColumnHack()
+         */
+        @NonNull
+        public CompleteBuilder nullColumnHack(@Nullable String nullColumnHack) {
+            this.nullColumnHack = nullColumnHack;
+            return this;
+        }
+
+        /**
+         * Builds immutable instance of {@link InsertQuery}.
+         *
+         * @return immutable instance of {@link InsertQuery}.
+         */
+        @NonNull
+        public InsertQuery build() {
+            return new InsertQuery(
+                    table,
+                    nullColumnHack
+            );
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/Query.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/Query.java
new file mode 100644
index 0000000..fafb654
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/Query.java
@@ -0,0 +1,500 @@
+package com.pushtorefresh.storio.sqlite.queries;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.List;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotEmpty;
+import static com.pushtorefresh.storio.internal.Queries.nonNullString;
+import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullListOfStrings;
+
+/**
+ * Get query for {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}.
+ * <p>
+ * Instances of this class are immutable.
+ */
+public class Query {
+
+    private final boolean distinct;
+
+    @NonNull
+    private final String table;
+
+    @NonNull
+    private final List<String> columns;
+
+    @NonNull
+    private final String where;
+
+    @NonNull
+    private final List<String> whereArgs;
+
+    @NonNull
+    private final String groupBy;
+
+    @NonNull
+    private final String having;
+
+    @NonNull
+    private final String orderBy;
+
+    @NonNull
+    private final String limit;
+
+    /**
+     * Please use {@link com.pushtorefresh.storio.sqlite.queries.Query.Builder}
+     * instead of constructor.
+     */
+    private Query(boolean distinct, @NonNull String table, @Nullable List<String> columns,
+                  @Nullable String where, @Nullable List<String> whereArgs,
+                  @Nullable String groupBy, @Nullable String having,
+                  @Nullable String orderBy, @Nullable String limit) {
+        this.distinct = distinct;
+        this.table = table;
+        this.columns = unmodifiableNonNullListOfStrings(columns);
+        this.where = nonNullString(where);
+        this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
+        this.groupBy = nonNullString(groupBy);
+        this.having = nonNullString(having);
+        this.orderBy = nonNullString(orderBy);
+        this.limit = nonNullString(limit);
+    }
+
+    /**
+     * Gets distinct option.
+     * <p>
+     * True if you want each row to be unique, false otherwise.
+     *
+     * @return distinct option.
+     */
+    public boolean distinct() {
+        return distinct;
+    }
+
+    /**
+     * Gets table name.
+     *
+     * @return non-null table name.
+     */
+    @NonNull
+    public String table() {
+        return table;
+    }
+
+    /**
+     * Gets optional immutable list of columns that should be received.
+     * <p>
+     * If list is empty -> all columns will be received.
+     *
+     * @return non-null, immutable list of columns that should be received.
+     */
+    @NonNull
+    public List<String> columns() {
+        return columns;
+    }
+
+    /**
+     * Gets {@code WHERE} clause.
+     * <p>
+     * Optional filter declaring which rows to return.
+     * <p>
+     * Formatted as an SQL {@code WHERE} clause (excluding the {@code WHERE} itself).
+     * <p>
+     * If empty — Query will retrieve all rows for the given table.
+     *
+     * @return non-null {@code WHERE} clause.
+     */
+    @NonNull
+    public String where() {
+        return where;
+    }
+
+    /**
+     * Gets optional immutable list of arguments for {@link #where()} clause.
+     *
+     * @return non-null, immutable list of arguments for {@code WHERE} clause.
+     */
+    @NonNull
+    public List<String> whereArgs() {
+        return whereArgs;
+    }
+
+    /**
+     * Gets {@code GROUP BY} clause.
+     * <p>
+     * Optional filter declaring how to group rows.
+     * <p>
+     * Formatted as an SQL {@code GROUP BY} clause (excluding the {@code GROUP BY} itself).
+     * <p>
+     * Passing {@code null} or empty string will cause the rows to not be grouped.
+     *
+     * @return non-null {@code GROUP BY} clause.
+     */
+    @NonNull
+    public String groupBy() {
+        return groupBy;
+    }
+
+    /**
+     * Gets having clause.
+     * <p>
+     * Optional filter declare which row groups to include
+     * in the cursor, if row grouping is being used.
+     * <p>
+     * Formatted as an SQL HAVING clause (excluding the HAVING itself).
+     * <p>
+     * Passing {@code null} or empty string will cause all row groups to be included,
+     * and is required when row grouping is not being used.
+     *
+     * @return non-null {@code HAVING} clause.
+     */
+    @NonNull
+    public String having() {
+        return having;
+    }
+
+    /**
+     * Gets {@code ORDER BY} clause.
+     * <p>
+     * Optional specifier to how to order the rows.
+     * <p>
+     * Formatted as an SQL {@code ORDER BY} clause (excluding the {@code ORDER BY} itself).
+     * <p>
+     * Passing {@code null} or empty string will use the default sort order, which may be unordered.
+     *
+     * @return non-null {@code ORDER BY} clause.
+     */
+    @NonNull
+    public String orderBy() {
+        return orderBy;
+    }
+
+    /**
+     * Gets {@code LIMIT} clause.
+     * <p>
+     * Optional specifier that limits the number of rows returned by the query.
+     * <p>
+     * Formatted as {@code LIMIT} clause.
+     * <p>
+     * Passing {@code null} or empty String denotes no {@code LIMIT} clause.
+     *
+     * @return non-null {@code LIMIT} clause.
+     */
+    @NonNull
+    public String limit() {
+        return limit;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Query query = (Query) o;
+
+        if (distinct != query.distinct) return false;
+        if (!table.equals(query.table)) return false;
+        if (!columns.equals(query.columns)) return false;
+        if (!where.equals(query.where)) return false;
+        if (!whereArgs.equals(query.whereArgs)) return false;
+        if (!groupBy.equals(query.groupBy)) return false;
+        if (!having.equals(query.having)) return false;
+        if (!orderBy.equals(query.orderBy)) return false;
+        return limit.equals(query.limit);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = (distinct ? 1 : 0);
+        result = 31 * result + table.hashCode();
+        result = 31 * result + columns.hashCode();
+        result = 31 * result + where.hashCode();
+        result = 31 * result + whereArgs.hashCode();
+        result = 31 * result + groupBy.hashCode();
+        result = 31 * result + having.hashCode();
+        result = 31 * result + orderBy.hashCode();
+        result = 31 * result + limit.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "Query{" +
+                "distinct=" + distinct +
+                ", table='" + table + '\'' +
+                ", columns=" + columns +
+                ", where='" + where + '\'' +
+                ", whereArgs=" + whereArgs +
+                ", groupBy='" + groupBy + '\'' +
+                ", having='" + having + '\'' +
+                ", orderBy='" + orderBy + '\'' +
+                ", limit='" + limit + '\'' +
+                '}';
+    }
+
+    /**
+     * Creates new builder for {@link Query}.
+     *
+     * @return non-null instance of {@link Query.Builder}.
+     */
+    @NonNull
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link Query}.
+     */
+    public static final class Builder {
+
+        /**
+         * Please use {@link Query#builder()} instead of this.
+         */
+        Builder() {
+        }
+
+        /**
+         * Required: Specifies table name.
+         *
+         * @param table non-null and not empty table name.
+         * @return builder.
+         * @see Query#table()
+         */
+        @NonNull
+        public CompleteBuilder table(@NonNull String table) {
+            checkNotEmpty(table, "Table name is null or empty");
+            return new CompleteBuilder(table);
+        }
+    }
+
+    /**
+     * Compile-time safe part of builder for {@link DeleteQuery}.
+     */
+    public static final class CompleteBuilder {
+
+        @NonNull
+        private final String table;
+
+        private boolean distinct;
+
+        private List<String> columns;
+
+        private String where;
+
+        private List<String> whereArgs;
+
+        private String groupBy;
+
+        private String having;
+
+        private String orderBy;
+
+        private String limit;
+
+        CompleteBuilder(@NonNull String table) {
+            this.table = table;
+        }
+
+        /**
+         * Optional: Specifies distinct option.
+         * <p>
+         * Set {@code true} if you want each row to be unique, {@code false} otherwise.
+         * <p>
+         * Default value is {@code false}.
+         *
+         * @param distinct distinct option.
+         * @return builder.
+         * @see Query#distinct()
+         */
+        @NonNull
+        public CompleteBuilder distinct(boolean distinct) {
+            this.distinct = distinct;
+            return this;
+        }
+
+        /**
+         * Optional: Specifies list of columns that should be received.
+         * <p>
+         * If list will be {@code null} or empty -> all columns will be received.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param columns list of columns to receive.
+         * @return builder.
+         * @see Query#columns()
+         */
+        @NonNull
+        public CompleteBuilder columns(@Nullable String... columns) {
+            this.columns = unmodifiableNonNullListOfStrings(columns);
+            return this;
+        }
+
+        /**
+         * Optional: Specifies {@code WHERE} clause.
+         * <p>
+         * Optional filter declaring which rows to return.
+         * <p>
+         * Formatted as an SQL {@code WHERE} clause (excluding the {@code WHERE} itself).
+         * <p>
+         * Passing {@code null} will RETURN all rows for the given table.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param where {@code WHERE} clause.
+         * @return builder.
+         * @see Query#where()
+         */
+        @NonNull
+        public CompleteBuilder where(@Nullable String where) {
+            this.where = where;
+            return this;
+        }
+
+        /**
+         * Optional: Specifies arguments for where clause.
+         * <p>
+         * Passed objects will be immediately converted list of
+         * to {@link String} via calling {@link Object#toString()}.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param whereArgs list of arguments for where clause.
+         * @return builder.
+         * @see Query#whereArgs()
+         */
+        @NonNull
+        public CompleteBuilder whereArgs(@Nullable Object... whereArgs) {
+            this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
+            return this;
+        }
+
+        /**
+         * Optional: Specifies arguments for where clause.
+         * <p>
+         * Passed objects will be immediately converted list of
+         * to {@link String} via calling {@link Object#toString()}.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param whereArgs list of arguments for where clause.
+         * @return builder.
+         * @see Query#whereArgs()
+         */
+        @NonNull
+        public CompleteBuilder whereArgs(@Nullable List<?> whereArgs) {
+            this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
+            return this;
+        }
+
+        /**
+         * Optional: Specifies {@code GROUP BY} clause.
+         * <p>
+         * Optional filter declaring how to group rows.
+         * <p>
+         * Formatted as an SQL {@code GROUP BY} clause (excluding the {@code GROUP BY} itself).
+         * <p>
+         * Passing {@code null} will cause the rows to not be grouped.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param groupBy {@code GROUP BY} clause.
+         * @return builder.
+         * @see Query#groupBy()
+         */
+        @NonNull
+        public CompleteBuilder groupBy(@Nullable String groupBy) {
+            this.groupBy = groupBy;
+            return this;
+        }
+
+        /**
+         * Optional: Specifies {@code HAVING} clause.
+         * <p>
+         * Optional filter declare which row groups to include in the cursor,
+         * if row grouping is being used.
+         * <p>
+         * Formatted as an SQL {@code HAVING} clause (excluding the {@code HAVING} itself).
+         * <p>
+         * Passing {@code null} will cause all row groups to be included,
+         * and is required when row grouping is not being used.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param having {@code HAVING} clause.
+         * @return builder.
+         * @see Query#having()
+         */
+        @NonNull
+        public CompleteBuilder having(@Nullable String having) {
+            this.having = having;
+            return this;
+        }
+
+        /**
+         * Optional: Specifies {@code ORDER BY} clause.
+         * <p>
+         * Optional specifier to how to order the rows.
+         * <p>
+         * Formatted as an SQL {@code ORDER BY} clause (excluding the {@code ORDER BY} itself).
+         * <p>
+         * Passing {@code null} will use the default sort order, which may be unordered.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param orderBy {@code ORDER BY} clause.
+         * @return builder.
+         * @see Query#orderBy()
+         */
+        @NonNull
+        public CompleteBuilder orderBy(@Nullable String orderBy) {
+            this.orderBy = orderBy;
+            return this;
+        }
+
+        /**
+         * Optional: Specifies {@code LIMIT} clause.
+         * <p>
+         * Optional specifier that limits the number of rows returned by the query.
+         * <p>
+         * Formatted as {@code LIMIT} clause.
+         * <p>
+         * Passing {@code null} denotes no {@code LIMIT} clause.
+         * <p>
+         * Default value is {@code null}.
+         *
+         * @param limit {@code LIMIT} clause.
+         * @return builder.
+         * @see Query#limit()
+         */
+        @NonNull
+        public CompleteBuilder limit(@Nullable String limit) {
+            this.limit = limit;
+            return this;
+        }
+
+        /**
+         * Builds immutable instance of {@link Query}.
+         *
+         * @return immutable instance of {@link Query}.
+         */
+        @NonNull
+        public Query build() {
+            if (where == null && whereArgs != null && !whereArgs.isEmpty()) {
+                throw new IllegalStateException("You can not use whereArgs without where clause");
+            }
+
+            return new Query(
+                    distinct,
+                    table,
+                    columns,
+                    where,
+                    whereArgs,
+                    groupBy,
+                    having,
+                    orderBy,
+                    limit
+            );
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/RawQuery.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/RawQuery.java
new file mode 100644
index 0000000..0eaf1d4
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/RawQuery.java
@@ -0,0 +1,249 @@
+package com.pushtorefresh.storio.sqlite.queries;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotEmpty;
+import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullListOfStrings;
+import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullSet;
+
+/**
+ * Raw SQL query for {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}.
+ * <p/>
+ * Instances of this class are immutable.
+ */
+public class RawQuery {
+
+    @NonNull
+    private final String query;
+
+    @NonNull
+    private final List<String> args;
+
+    @NonNull
+    private final Set<String> affectsTables;
+
+    @NonNull
+    private final Set<String> observesTables;
+
+    /**
+     * Please use {@link com.pushtorefresh.storio.sqlite.queries.RawQuery.Builder}
+     * instead of constructor.
+     */
+    private RawQuery(@NonNull String query, @Nullable List<String> args,
+                     @Nullable Set<String> affectsTables, @Nullable Set<String> observesTables) {
+        this.query = query;
+        this.args = unmodifiableNonNullListOfStrings(args);
+        this.affectsTables = unmodifiableNonNullSet(affectsTables);
+        this.observesTables = unmodifiableNonNullSet(observesTables);
+    }
+
+    /**
+     * Raw SQL query. Can contain {@code ?} for binding arguments.
+     *
+     * @return non-null SQL query.
+     */
+    @NonNull
+    public String query() {
+        return query;
+    }
+
+    /**
+     * Gets optional immutable list of arguments for {@link #query()}.
+     *
+     * @return non-null, immutable list of arguments for query.
+     */
+    @NonNull
+    public List<String> args() {
+        return args;
+    }
+
+    /**
+     * Gets optional immutable set of tables which will be affected by this query.
+     * <p/>
+     * They will be used to notify observers of that tables.
+     *
+     * @return non-null, immutable set of tables, affected by this query.
+     */
+    @NonNull
+    public Set<String> affectsTables() {
+        return affectsTables;
+    }
+
+    /**
+     * Gets optional immutable set of tables that should be observed by this query.
+     * <p/>
+     * They will be used to observe changes of that tables and re-execute this query.
+     *
+     * @return non-null, immutable set of tables, that should be observed by this query.
+     */
+    @NonNull
+    public Set<String> observesTables() {
+        return observesTables;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        RawQuery rawQuery = (RawQuery) o;
+
+        if (!query.equals(rawQuery.query)) return false;
+        if (!args.equals(rawQuery.args)) return false;
+        if (!affectsTables.equals(rawQuery.affectsTables)) return false;
+        return observesTables.equals(rawQuery.observesTables);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = query.hashCode();
+        result = 31 * result + args.hashCode();
+        result = 31 * result + affectsTables.hashCode();
+        result = 31 * result + observesTables.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "RawQuery{" +
+                "query='" + query + '\'' +
+                ", args=" + args +
+                ", affectsTables=" + affectsTables +
+                ", observesTables=" + observesTables +
+                '}';
+    }
+
+    /**
+     * Creates new builder for {@link RawQuery}.
+     *
+     * @return non-null instance of {@link RawQuery.Builder}.
+     */
+    @NonNull
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link RawQuery}.
+     */
+    public static final class Builder {
+
+        /**
+         * Please use {@link RawQuery#builder()} instead of this.
+         */
+        Builder() {
+        }
+
+        /**
+         * Required: Specifies SQL query.
+         *
+         * @param query SQL query.
+         * @return builder.
+         * @see RawQuery#query()
+         */
+        @NonNull
+        public CompleteBuilder query(@NonNull String query) {
+            checkNotEmpty(query, "Query is null or empty");
+            return new CompleteBuilder(query);
+        }
+    }
+
+    /**
+     * Compile-time safe part of builder for {@link DeleteQuery}
+     */
+    public static final class CompleteBuilder {
+
+        @NonNull
+        private final String query;
+
+        private List<String> args;
+
+        private Set<String> affectsTables;
+
+        private Set<String> observesTables;
+
+        CompleteBuilder(@NonNull String query) {
+            this.query = query;
+        }
+
+        /**
+         * Optional: Specifies arguments for SQL query,
+         * please use arguments to avoid SQL injections.
+         * <p/>
+         * Passed objects will be immediately converted
+         * to list of {@link String} via calling {@link Object#toString()}.
+         * <p/>
+         * Default value is {@code null}.
+         *
+         * @param args arguments fro SQL query.
+         * @return builder.
+         * @see RawQuery#args()
+         */
+        @NonNull
+        public CompleteBuilder args(@NonNull Object... args) {
+            this.args = unmodifiableNonNullListOfStrings(args);
+            return this;
+        }
+
+        /**
+         * Optional: Specifies set of tables which will be affected by this query.
+         * They will be used to notify observers of that tables.
+         * <p/>
+         * Default value is {@code null}.
+         *
+         * @param tables set of tables which will be affected by this query.
+         * @return builder.
+         * @see RawQuery#affectsTables()
+         */
+        @NonNull
+        public CompleteBuilder affectsTables(@NonNull String... tables) {
+            if (this.affectsTables == null) {
+                this.affectsTables = new HashSet<String>(tables.length);
+            }
+
+            Collections.addAll(this.affectsTables, tables);
+            return this;
+        }
+
+        /**
+         * Optional: Specifies set of tables that should be observed by this query.
+         * They will be used to re-execute query if one of the tables will be changed.
+         * <p/>
+         * Default values is {@code null}.
+         *
+         * @param tables set of tables that should be observed by this query.
+         * @return builder.
+         * @see RawQuery#observesTables()
+         */
+        @NonNull
+        public CompleteBuilder observesTables(@NonNull String... tables) {
+            if (this.observesTables == null) {
+                this.observesTables = new HashSet<String>(tables.length);
+            }
+
+            Collections.addAll(this.observesTables, tables);
+            return this;
+        }
+
+        /**
+         * Builds immutable instance of {@link RawQuery}.
+         *
+         * @return immutable instance of {@link RawQuery}.
+         */
+        @NonNull
+        public RawQuery build() {
+            return new RawQuery(
+                    query,
+                    args,
+                    affectsTables,
+                    observesTables
+            );
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/UpdateQuery.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/UpdateQuery.java
new file mode 100644
index 0000000..e9dc683
--- /dev/null
+++ b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/queries/UpdateQuery.java
@@ -0,0 +1,207 @@
+package com.pushtorefresh.storio.sqlite.queries;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.List;
+
+import static com.pushtorefresh.storio.internal.Checks.checkNotEmpty;
+import static com.pushtorefresh.storio.internal.Queries.nonNullString;
+import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullListOfStrings;
+
+/**
+ * Update query for {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}.
+ * <p/>
+ * Instances of this class are immutable.
+ */
+public final class UpdateQuery {
+
+    @NonNull
+    private final String table;
+
+    @NonNull
+    private final String where;
+
+    @NonNull
+    private final List<String> whereArgs;
+
+    /**
+     * Please use {@link com.pushtorefresh.storio.sqlite.queries.UpdateQuery.Builder}
+     * instead of constructor.
+     */
+    private UpdateQuery(@NonNull String table, @Nullable String where, @Nullable List<String> whereArgs) {
+        this.table = table;
+        this.where = nonNullString(where);
+        this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
+    }
+
+    /**
+     * Gets table name.
+     *
+     * @return non-null table name.
+     */
+    @NonNull
+    public String table() {
+        return table;
+    }
+
+    /**
+     * Gets {@code WHERE} clause.
+     * <p/>
+     * Optional filter declaring which rows to update.
+     * <p/>
+     * Formatted as an SQL {@code WHERE} clause (excluding the {@code WHERE} itself).
+     * <p/>
+     * If empty — Query will update all rows for the given table.
+     *
+     * @return non-null {@code WHERE} clause.
+     */
+    @NonNull
+    public String where() {
+        return where;
+    }
+
+    /**
+     * Gets optional immutable list of arguments for {@link #where()} clause.
+     *
+     * @return non-null, immutable list of arguments for {@code WHERE} clause.
+     */
+    @NonNull
+    public List<String> whereArgs() {
+        return whereArgs;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        UpdateQuery that = (UpdateQuery) o;
+
+        if (!table.equals(that.table)) return false;
+        if (!where.equals(that.where)) return false;
+        return whereArgs.equals(that.whereArgs);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = table.hashCode();
+        result = 31 * result + where.hashCode();
+        result = 31 * result + whereArgs.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "UpdateQuery{" +
+                "table='" + table + '\'' +
+                ", where='" + where + '\'' +
+                ", whereArgs=" + whereArgs +
+                '}';
+    }
+
+    /**
+     * Creates new builder for {@link UpdateQuery}.
+     *
+     * @return non-null instance of {@link UpdateQuery.Builder}.
+     */
+    @NonNull
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * Builder for {@link UpdateQuery}.
+     */
+    public static final class Builder {
+
+        /**
+         * Please use {@link UpdateQuery#builder()} instead of this.
+         */
+        Builder() {
+        }
+
+        /**
+         * Required: Specifies table name.
+         *
+         * @param table non-null table name.
+         * @return builder.
+         * @see UpdateQuery#table()
+         */
+        @NonNull
+        public CompleteBuilder table(@NonNull String table) {
+            checkNotEmpty(table, "Table name is null or empty");
+            return new CompleteBuilder(table);
+        }
+    }
+
+    /**
+     * Compile-time safe part of builder for {@link DeleteQuery}.
+     */
+    public static final class CompleteBuilder {
+
+        @NonNull
+        private final String table;
+
+        private String where;
+
+        private List<String> whereArgs;
+
+        CompleteBuilder(@NonNull String table) {
+            this.table = table;
+        }
+
+        /**
+         * Optional: Specifies {@code WHERE} clause.
+         * <p/>
+         * Optional filter declaring which rows to return.
+         * <p/>
+         * Formatted as an SQL WHERE clause (excluding the {@code WHERE} itself).
+         * <p/>
+         * Passing {@code null} will UPDATE all rows for the given table.
+         * <p/>
+         * Default value is {@code null}.
+         *
+         * @param where {@code WHERE} clause.
+         * @return builder.
+         * @see UpdateQuery#where()
+         */
+        @NonNull
+        public CompleteBuilder where(@Nullable String where) {
+            this.where = where;
+            return this;
+        }
+
+        /**
+         * Optional: Specifies arguments for {@code WHERE} clause.
+         * <p/>
+         * Passed objects will be immediately converted
+         * to list of {@link String} via calling {@link Object#toString()}.
+         * <p/>
+         * Default value is {@code null}.
+         *
+         * @param whereArgs list of arguments for {@code WHERE} clause.
+         * @return builder.
+         * @see UpdateQuery#whereArgs()
+         */
+        @NonNull
+        public CompleteBuilder whereArgs(@Nullable Object... whereArgs) {
+            this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
+            return this;
+        }
+
+        /**
+         * Builds immutable instance of {@link UpdateQuery}.
+         *
+         * @return immutable instance of {@link UpdateQuery}.
+         */
+        @NonNull
+        public UpdateQuery build() {
+            return new UpdateQuery(
+                    table,
+                    where,
+                    whereArgs
+            );
+        }
+    }
+}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/DeleteQuery.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/DeleteQuery.java
deleted file mode 100644
index 54ade22..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/DeleteQuery.java
+++ /dev/null
@@ -1,211 +0,0 @@
-package com.pushtorefresh.storio.sqlite.query;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import java.util.List;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotEmpty;
-import static com.pushtorefresh.storio.internal.Queries.nonNullString;
-import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullListOfStrings;
-
-/**
- * Delete query for {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}.
- * <p>
- * Instances of this class are immutable.
- */
-public final class DeleteQuery {
-
-    @NonNull
-    private final String table;
-
-    @NonNull
-    private final String where;
-
-    @NonNull
-    private final List<String> whereArgs;
-
-    /**
-     * Please use {@link com.pushtorefresh.storio.sqlite.query.DeleteQuery.Builder}
-     * instead of constructor.
-     */
-    private DeleteQuery(@NonNull String table, @Nullable String where, @Nullable List<String> whereArgs) {
-        this.table = table;
-        this.where = nonNullString(where);
-        this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
-    }
-
-    /**
-     * Gets table name.
-     *
-     * @return non-null table name.
-     */
-    @NonNull
-    public String table() {
-        return table;
-    }
-
-    /**
-     * Gets {@code WHERE} clause.
-     * <p>
-     * Optional filter declaring which rows to return.
-     * <p>
-     * Formatted as an SQL {@code WHERE} clause (excluding the {@code WHERE} itself).
-     * <p>
-     * If empty — Query will delete all rows for the given table.
-     *
-     * @return non-null {@code WHERE} clause.
-     */
-    @NonNull
-    public String where() {
-        return where;
-    }
-
-    /**
-     * Gets optional immutable list of arguments for {@link #where()} clause.
-     *
-     * @return non-null, immutable list of arguments for {@code WHERE} clause.
-     */
-    @NonNull
-    public List<String> whereArgs() {
-        return whereArgs;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        DeleteQuery that = (DeleteQuery) o;
-
-        if (!table.equals(that.table)) return false;
-        if (!where.equals(that.where)) return false;
-        return whereArgs.equals(that.whereArgs);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = table.hashCode();
-        result = 31 * result + where.hashCode();
-        result = 31 * result + whereArgs.hashCode();
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "DeleteQuery{" +
-                "table='" + table + '\'' +
-                ", where='" + where + '\'' +
-                ", whereArgs=" + whereArgs +
-                '}';
-    }
-
-    /**
-     * Creates new builder for {@link DeleteQuery}.
-     *
-     * @return non-null instance of {@link DeleteQuery.Builder}.
-     */
-    @NonNull
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    /**
-     * Builder for {@link DeleteQuery}.
-     */
-    public static final class Builder {
-
-        /**
-         * Please use {@link DeleteQuery#builder()} instead of this.
-         */
-        Builder() {
-        }
-
-        /**
-         * Required: Specifies table name.
-         *
-         * @param table non-null and not empty table name.
-         * @return builder.
-         * @see DeleteQuery#table()
-         */
-        @NonNull
-        public CompleteBuilder table(@NonNull String table) {
-            checkNotEmpty(table, "Table name is null or empty");
-            return new CompleteBuilder(table);
-        }
-    }
-
-    /**
-     * Compile-time safe part of builder for {@link DeleteQuery}.
-     */
-    public static final class CompleteBuilder {
-
-        @NonNull
-        private final String table;
-
-        private String where;
-
-        private List<String> whereArgs;
-
-        CompleteBuilder(@NonNull String table) {
-            this.table = table;
-        }
-
-        /**
-         * Optional: Specifies {@code WHERE} clause.
-         * <p>
-         * Optional filter declaring which rows to return.
-         * <p>
-         * Formatted as an SQL WHERE clause (excluding the WHERE itself).
-         * <p>
-         * Passing null will DELETE all rows for the given table.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param where {@code WHERE} clause.
-         * @return builder.
-         * @see DeleteQuery#where()
-         */
-        @NonNull
-        public CompleteBuilder where(@Nullable String where) {
-            this.where = where;
-            return this;
-        }
-
-        /**
-         * Optional: Specifies arguments for {@code WHERE} clause.
-         * <p>
-         * Passed objects will be immediately converted
-         * to list of {@link String} via calling {@link Object#toString()}.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param whereArgs list of arguments for {@code WHERE} clause.
-         * @return builder.
-         * @see DeleteQuery#whereArgs()
-         */
-        @NonNull
-        public CompleteBuilder whereArgs(@Nullable Object... whereArgs) {
-            this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
-            return this;
-        }
-
-        /**
-         * Builds immutable instance of {@link DeleteQuery}.
-         *
-         * @return immutable instance of {@link DeleteQuery}.
-         */
-        @NonNull
-        public DeleteQuery build() {
-            if (where == null && whereArgs != null && !whereArgs.isEmpty()) {
-                throw new IllegalStateException("You can not use whereArgs without where clause");
-            }
-
-            return new DeleteQuery(
-                    table,
-                    where,
-                    whereArgs
-            );
-        }
-    }
-}
\ No newline at end of file
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/InsertQuery.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/InsertQuery.java
deleted file mode 100644
index e2a835e..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/InsertQuery.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package com.pushtorefresh.storio.sqlite.query;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotEmpty;
-
-/**
- * Insert query for {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}.
- * <p/>
- * Instances of this class are immutable.
- */
-public final class InsertQuery {
-
-    @NonNull
-    private final String table;
-
-    @Nullable
-    private final String nullColumnHack;
-
-    /**
-     * Please use {@link com.pushtorefresh.storio.sqlite.query.InsertQuery.Builder}
-     * instead of constructor.
-     */
-    private InsertQuery(@NonNull String table, @Nullable String nullColumnHack) {
-        this.table = table;
-        this.nullColumnHack = nullColumnHack;
-    }
-
-    /**
-     * Gets table name.
-     *
-     * @return non-null table name.
-     */
-    @NonNull
-    public String table() {
-        return table;
-    }
-
-    /**
-     * Gets tricky-wiki hack for {@code null} columns in
-     * {@link android.database.sqlite.SQLiteDatabase}.
-     * <p/>
-     * SQL doesn't allow inserting a completely empty row
-     * without naming at least one column name. If your provided values
-     * are empty, no column names are known and an empty row can't be
-     * inserted. If not set to {@code null}, the {@code nullColumnHack}
-     * parameter provides the name of nullable column name to explicitly
-     * insert a {@code NULL} into in the case where your values is empty.
-     *
-     * @return nullable hack for {@code NULL} columns.
-     */
-    @Nullable
-    public String nullColumnHack() {
-        return nullColumnHack;
-    }
-
-    @Override
-    public boolean equals(@Nullable Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        InsertQuery that = (InsertQuery) o;
-
-        if (nullColumnHack != null ? !nullColumnHack.equals(that.nullColumnHack) : that.nullColumnHack != null)
-            return false;
-        if (!table.equals(that.table)) return false;
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = table.hashCode();
-        result = 31 * result + (nullColumnHack != null ? nullColumnHack.hashCode() : 0);
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "InsertQuery{" +
-                "table='" + table + '\'' +
-                ", nullColumnHack='" + nullColumnHack + '\'' +
-                '}';
-    }
-
-    /**
-     * Creates new builder for {@link InsertQuery}.
-     *
-     * @return non-null instance of {@link InsertQuery.Builder}.
-     */
-    @NonNull
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    /**
-     * Builder for {@link InsertQuery}.
-     */
-    public static final class Builder {
-
-        /**
-         * Please use {@link InsertQuery#builder()} instead of this.
-         */
-        Builder() {
-        }
-
-        /**
-         * Required: Specifies table name.
-         *
-         * @param table non-null and not empty table name.
-         * @return builder.
-         * @see InsertQuery#table()
-         */
-        @NonNull
-        public CompleteBuilder table(@NonNull String table) {
-            checkNotEmpty(table, "Table name is null or empty");
-            return new CompleteBuilder(table);
-        }
-    }
-
-    /**
-     * Compile-time safe part of builder for {@link DeleteQuery}.
-     */
-    public static final class CompleteBuilder {
-
-        @NonNull
-        private final String table;
-
-        private String nullColumnHack;
-
-        CompleteBuilder(@NonNull String table) {
-            this.table = table;
-        }
-
-        /**
-         * Optional: Specifies {@code NULL} column hack.
-         * <p/>
-         * SQL doesn't allow inserting a completely empty row without naming at least one column name.
-         * If your provided values are empty, no column names are known and an empty row can't be inserted.
-         * If not set to null, the nullColumnHack parameter provides the name of nullable column name
-         * to explicitly insert a NULL into in the case where your values is empty.
-         * <p/>
-         * Default value is {@code null}.
-         *
-         * @param nullColumnHack optional null column hack.
-         * @return builder.
-         * @see InsertQuery#nullColumnHack()
-         */
-        @NonNull
-        public CompleteBuilder nullColumnHack(@Nullable String nullColumnHack) {
-            this.nullColumnHack = nullColumnHack;
-            return this;
-        }
-
-        /**
-         * Builds immutable instance of {@link InsertQuery}.
-         *
-         * @return immutable instance of {@link InsertQuery}.
-         */
-        @NonNull
-        public InsertQuery build() {
-            return new InsertQuery(
-                    table,
-                    nullColumnHack
-            );
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/Query.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/Query.java
deleted file mode 100644
index 170ba6e..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/Query.java
+++ /dev/null
@@ -1,500 +0,0 @@
-package com.pushtorefresh.storio.sqlite.query;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import java.util.List;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotEmpty;
-import static com.pushtorefresh.storio.internal.Queries.nonNullString;
-import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullListOfStrings;
-
-/**
- * Get query for {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}.
- * <p>
- * Instances of this class are immutable.
- */
-public class Query {
-
-    private final boolean distinct;
-
-    @NonNull
-    private final String table;
-
-    @NonNull
-    private final List<String> columns;
-
-    @NonNull
-    private final String where;
-
-    @NonNull
-    private final List<String> whereArgs;
-
-    @NonNull
-    private final String groupBy;
-
-    @NonNull
-    private final String having;
-
-    @NonNull
-    private final String orderBy;
-
-    @NonNull
-    private final String limit;
-
-    /**
-     * Please use {@link com.pushtorefresh.storio.sqlite.query.Query.Builder}
-     * instead of constructor.
-     */
-    private Query(boolean distinct, @NonNull String table, @Nullable List<String> columns,
-                  @Nullable String where, @Nullable List<String> whereArgs,
-                  @Nullable String groupBy, @Nullable String having,
-                  @Nullable String orderBy, @Nullable String limit) {
-        this.distinct = distinct;
-        this.table = table;
-        this.columns = unmodifiableNonNullListOfStrings(columns);
-        this.where = nonNullString(where);
-        this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
-        this.groupBy = nonNullString(groupBy);
-        this.having = nonNullString(having);
-        this.orderBy = nonNullString(orderBy);
-        this.limit = nonNullString(limit);
-    }
-
-    /**
-     * Gets distinct option.
-     * <p>
-     * True if you want each row to be unique, false otherwise.
-     *
-     * @return distinct option.
-     */
-    public boolean distinct() {
-        return distinct;
-    }
-
-    /**
-     * Gets table name.
-     *
-     * @return non-null table name.
-     */
-    @NonNull
-    public String table() {
-        return table;
-    }
-
-    /**
-     * Gets optional immutable list of columns that should be received.
-     * <p>
-     * If list is empty -> all columns will be received.
-     *
-     * @return non-null, immutable list of columns that should be received.
-     */
-    @NonNull
-    public List<String> columns() {
-        return columns;
-    }
-
-    /**
-     * Gets {@code WHERE} clause.
-     * <p>
-     * Optional filter declaring which rows to return.
-     * <p>
-     * Formatted as an SQL {@code WHERE} clause (excluding the {@code WHERE} itself).
-     * <p>
-     * If empty — Query will retrieve all rows for the given table.
-     *
-     * @return non-null {@code WHERE} clause.
-     */
-    @NonNull
-    public String where() {
-        return where;
-    }
-
-    /**
-     * Gets optional immutable list of arguments for {@link #where()} clause.
-     *
-     * @return non-null, immutable list of arguments for {@code WHERE} clause.
-     */
-    @NonNull
-    public List<String> whereArgs() {
-        return whereArgs;
-    }
-
-    /**
-     * Gets {@code GROUP BY} clause.
-     * <p>
-     * Optional filter declaring how to group rows.
-     * <p>
-     * Formatted as an SQL {@code GROUP BY} clause (excluding the {@code GROUP BY} itself).
-     * <p>
-     * Passing {@code null} or empty string will cause the rows to not be grouped.
-     *
-     * @return non-null {@code GROUP BY} clause.
-     */
-    @NonNull
-    public String groupBy() {
-        return groupBy;
-    }
-
-    /**
-     * Gets having clause.
-     * <p>
-     * Optional filter declare which row groups to include
-     * in the cursor, if row grouping is being used.
-     * <p>
-     * Formatted as an SQL HAVING clause (excluding the HAVING itself).
-     * <p>
-     * Passing {@code null} or empty string will cause all row groups to be included,
-     * and is required when row grouping is not being used.
-     *
-     * @return non-null {@code HAVING} clause.
-     */
-    @NonNull
-    public String having() {
-        return having;
-    }
-
-    /**
-     * Gets {@code ORDER BY} clause.
-     * <p>
-     * Optional specifier to how to order the rows.
-     * <p>
-     * Formatted as an SQL {@code ORDER BY} clause (excluding the {@code ORDER BY} itself).
-     * <p>
-     * Passing {@code null} or empty string will use the default sort order, which may be unordered.
-     *
-     * @return non-null {@code ORDER BY} clause.
-     */
-    @NonNull
-    public String orderBy() {
-        return orderBy;
-    }
-
-    /**
-     * Gets {@code LIMIT} clause.
-     * <p>
-     * Optional specifier that limits the number of rows returned by the query.
-     * <p>
-     * Formatted as {@code LIMIT} clause.
-     * <p>
-     * Passing {@code null} or empty String denotes no {@code LIMIT} clause.
-     *
-     * @return non-null {@code LIMIT} clause.
-     */
-    @NonNull
-    public String limit() {
-        return limit;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        Query query = (Query) o;
-
-        if (distinct != query.distinct) return false;
-        if (!table.equals(query.table)) return false;
-        if (!columns.equals(query.columns)) return false;
-        if (!where.equals(query.where)) return false;
-        if (!whereArgs.equals(query.whereArgs)) return false;
-        if (!groupBy.equals(query.groupBy)) return false;
-        if (!having.equals(query.having)) return false;
-        if (!orderBy.equals(query.orderBy)) return false;
-        return limit.equals(query.limit);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = (distinct ? 1 : 0);
-        result = 31 * result + table.hashCode();
-        result = 31 * result + columns.hashCode();
-        result = 31 * result + where.hashCode();
-        result = 31 * result + whereArgs.hashCode();
-        result = 31 * result + groupBy.hashCode();
-        result = 31 * result + having.hashCode();
-        result = 31 * result + orderBy.hashCode();
-        result = 31 * result + limit.hashCode();
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "Query{" +
-                "distinct=" + distinct +
-                ", table='" + table + '\'' +
-                ", columns=" + columns +
-                ", where='" + where + '\'' +
-                ", whereArgs=" + whereArgs +
-                ", groupBy='" + groupBy + '\'' +
-                ", having='" + having + '\'' +
-                ", orderBy='" + orderBy + '\'' +
-                ", limit='" + limit + '\'' +
-                '}';
-    }
-
-    /**
-     * Creates new builder for {@link Query}.
-     *
-     * @return non-null instance of {@link Query.Builder}.
-     */
-    @NonNull
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    /**
-     * Builder for {@link Query}.
-     */
-    public static final class Builder {
-
-        /**
-         * Please use {@link Query#builder()} instead of this.
-         */
-        Builder() {
-        }
-
-        /**
-         * Required: Specifies table name.
-         *
-         * @param table non-null and not empty table name.
-         * @return builder.
-         * @see Query#table()
-         */
-        @NonNull
-        public CompleteBuilder table(@NonNull String table) {
-            checkNotEmpty(table, "Table name is null or empty");
-            return new CompleteBuilder(table);
-        }
-    }
-
-    /**
-     * Compile-time safe part of builder for {@link DeleteQuery}.
-     */
-    public static final class CompleteBuilder {
-
-        @NonNull
-        private final String table;
-
-        private boolean distinct;
-
-        private List<String> columns;
-
-        private String where;
-
-        private List<String> whereArgs;
-
-        private String groupBy;
-
-        private String having;
-
-        private String orderBy;
-
-        private String limit;
-
-        CompleteBuilder(@NonNull String table) {
-            this.table = table;
-        }
-
-        /**
-         * Optional: Specifies distinct option.
-         * <p>
-         * Set {@code true} if you want each row to be unique, {@code false} otherwise.
-         * <p>
-         * Default value is {@code false}.
-         *
-         * @param distinct distinct option.
-         * @return builder.
-         * @see Query#distinct()
-         */
-        @NonNull
-        public CompleteBuilder distinct(boolean distinct) {
-            this.distinct = distinct;
-            return this;
-        }
-
-        /**
-         * Optional: Specifies list of columns that should be received.
-         * <p>
-         * If list will be {@code null} or empty -> all columns will be received.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param columns list of columns to receive.
-         * @return builder.
-         * @see Query#columns()
-         */
-        @NonNull
-        public CompleteBuilder columns(@Nullable String... columns) {
-            this.columns = unmodifiableNonNullListOfStrings(columns);
-            return this;
-        }
-
-        /**
-         * Optional: Specifies {@code WHERE} clause.
-         * <p>
-         * Optional filter declaring which rows to return.
-         * <p>
-         * Formatted as an SQL {@code WHERE} clause (excluding the {@code WHERE} itself).
-         * <p>
-         * Passing {@code null} will RETURN all rows for the given table.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param where {@code WHERE} clause.
-         * @return builder.
-         * @see Query#where()
-         */
-        @NonNull
-        public CompleteBuilder where(@Nullable String where) {
-            this.where = where;
-            return this;
-        }
-
-        /**
-         * Optional: Specifies arguments for where clause.
-         * <p>
-         * Passed objects will be immediately converted list of
-         * to {@link String} via calling {@link Object#toString()}.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param whereArgs list of arguments for where clause.
-         * @return builder.
-         * @see Query#whereArgs()
-         */
-        @NonNull
-        public CompleteBuilder whereArgs(@Nullable Object... whereArgs) {
-            this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
-            return this;
-        }
-
-        /**
-         * Optional: Specifies arguments for where clause.
-         * <p>
-         * Passed objects will be immediately converted list of
-         * to {@link String} via calling {@link Object#toString()}.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param whereArgs list of arguments for where clause.
-         * @return builder.
-         * @see Query#whereArgs()
-         */
-        @NonNull
-        public CompleteBuilder whereArgs(@Nullable List<?> whereArgs) {
-            this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
-            return this;
-        }
-
-        /**
-         * Optional: Specifies {@code GROUP BY} clause.
-         * <p>
-         * Optional filter declaring how to group rows.
-         * <p>
-         * Formatted as an SQL {@code GROUP BY} clause (excluding the {@code GROUP BY} itself).
-         * <p>
-         * Passing {@code null} will cause the rows to not be grouped.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param groupBy {@code GROUP BY} clause.
-         * @return builder.
-         * @see Query#groupBy()
-         */
-        @NonNull
-        public CompleteBuilder groupBy(@Nullable String groupBy) {
-            this.groupBy = groupBy;
-            return this;
-        }
-
-        /**
-         * Optional: Specifies {@code HAVING} clause.
-         * <p>
-         * Optional filter declare which row groups to include in the cursor,
-         * if row grouping is being used.
-         * <p>
-         * Formatted as an SQL {@code HAVING} clause (excluding the {@code HAVING} itself).
-         * <p>
-         * Passing {@code null} will cause all row groups to be included,
-         * and is required when row grouping is not being used.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param having {@code HAVING} clause.
-         * @return builder.
-         * @see Query#having()
-         */
-        @NonNull
-        public CompleteBuilder having(@Nullable String having) {
-            this.having = having;
-            return this;
-        }
-
-        /**
-         * Optional: Specifies {@code ORDER BY} clause.
-         * <p>
-         * Optional specifier to how to order the rows.
-         * <p>
-         * Formatted as an SQL {@code ORDER BY} clause (excluding the {@code ORDER BY} itself).
-         * <p>
-         * Passing {@code null} will use the default sort order, which may be unordered.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param orderBy {@code ORDER BY} clause.
-         * @return builder.
-         * @see Query#orderBy()
-         */
-        @NonNull
-        public CompleteBuilder orderBy(@Nullable String orderBy) {
-            this.orderBy = orderBy;
-            return this;
-        }
-
-        /**
-         * Optional: Specifies {@code LIMIT} clause.
-         * <p>
-         * Optional specifier that limits the number of rows returned by the query.
-         * <p>
-         * Formatted as {@code LIMIT} clause.
-         * <p>
-         * Passing {@code null} denotes no {@code LIMIT} clause.
-         * <p>
-         * Default value is {@code null}.
-         *
-         * @param limit {@code LIMIT} clause.
-         * @return builder.
-         * @see Query#limit()
-         */
-        @NonNull
-        public CompleteBuilder limit(@Nullable String limit) {
-            this.limit = limit;
-            return this;
-        }
-
-        /**
-         * Builds immutable instance of {@link Query}.
-         *
-         * @return immutable instance of {@link Query}.
-         */
-        @NonNull
-        public Query build() {
-            if (where == null && whereArgs != null && !whereArgs.isEmpty()) {
-                throw new IllegalStateException("You can not use whereArgs without where clause");
-            }
-
-            return new Query(
-                    distinct,
-                    table,
-                    columns,
-                    where,
-                    whereArgs,
-                    groupBy,
-                    having,
-                    orderBy,
-                    limit
-            );
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/RawQuery.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/RawQuery.java
deleted file mode 100644
index dff4478..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/RawQuery.java
+++ /dev/null
@@ -1,249 +0,0 @@
-package com.pushtorefresh.storio.sqlite.query;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotEmpty;
-import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullListOfStrings;
-import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullSet;
-
-/**
- * Raw SQL query for {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}.
- * <p/>
- * Instances of this class are immutable.
- */
-public class RawQuery {
-
-    @NonNull
-    private final String query;
-
-    @NonNull
-    private final List<String> args;
-
-    @NonNull
-    private final Set<String> affectsTables;
-
-    @NonNull
-    private final Set<String> observesTables;
-
-    /**
-     * Please use {@link com.pushtorefresh.storio.sqlite.query.RawQuery.Builder}
-     * instead of constructor.
-     */
-    private RawQuery(@NonNull String query, @Nullable List<String> args,
-                     @Nullable Set<String> affectsTables, @Nullable Set<String> observesTables) {
-        this.query = query;
-        this.args = unmodifiableNonNullListOfStrings(args);
-        this.affectsTables = unmodifiableNonNullSet(affectsTables);
-        this.observesTables = unmodifiableNonNullSet(observesTables);
-    }
-
-    /**
-     * Raw SQL query. Can contain {@code ?} for binding arguments.
-     *
-     * @return non-null SQL query.
-     */
-    @NonNull
-    public String query() {
-        return query;
-    }
-
-    /**
-     * Gets optional immutable list of arguments for {@link #query()}.
-     *
-     * @return non-null, immutable list of arguments for query.
-     */
-    @NonNull
-    public List<String> args() {
-        return args;
-    }
-
-    /**
-     * Gets optional immutable set of tables which will be affected by this query.
-     * <p/>
-     * They will be used to notify observers of that tables.
-     *
-     * @return non-null, immutable set of tables, affected by this query.
-     */
-    @NonNull
-    public Set<String> affectsTables() {
-        return affectsTables;
-    }
-
-    /**
-     * Gets optional immutable set of tables that should be observed by this query.
-     * <p/>
-     * They will be used to observe changes of that tables and re-execute this query.
-     *
-     * @return non-null, immutable set of tables, that should be observed by this query.
-     */
-    @NonNull
-    public Set<String> observesTables() {
-        return observesTables;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        RawQuery rawQuery = (RawQuery) o;
-
-        if (!query.equals(rawQuery.query)) return false;
-        if (!args.equals(rawQuery.args)) return false;
-        if (!affectsTables.equals(rawQuery.affectsTables)) return false;
-        return observesTables.equals(rawQuery.observesTables);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = query.hashCode();
-        result = 31 * result + args.hashCode();
-        result = 31 * result + affectsTables.hashCode();
-        result = 31 * result + observesTables.hashCode();
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "RawQuery{" +
-                "query='" + query + '\'' +
-                ", args=" + args +
-                ", affectsTables=" + affectsTables +
-                ", observesTables=" + observesTables +
-                '}';
-    }
-
-    /**
-     * Creates new builder for {@link RawQuery}.
-     *
-     * @return non-null instance of {@link RawQuery.Builder}.
-     */
-    @NonNull
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    /**
-     * Builder for {@link RawQuery}.
-     */
-    public static final class Builder {
-
-        /**
-         * Please use {@link RawQuery#builder()} instead of this.
-         */
-        Builder() {
-        }
-
-        /**
-         * Required: Specifies SQL query.
-         *
-         * @param query SQL query.
-         * @return builder.
-         * @see RawQuery#query()
-         */
-        @NonNull
-        public CompleteBuilder query(@NonNull String query) {
-            checkNotEmpty(query, "Query is null or empty");
-            return new CompleteBuilder(query);
-        }
-    }
-
-    /**
-     * Compile-time safe part of builder for {@link DeleteQuery}
-     */
-    public static final class CompleteBuilder {
-
-        @NonNull
-        private final String query;
-
-        private List<String> args;
-
-        private Set<String> affectsTables;
-
-        private Set<String> observesTables;
-
-        CompleteBuilder(@NonNull String query) {
-            this.query = query;
-        }
-
-        /**
-         * Optional: Specifies arguments for SQL query,
-         * please use arguments to avoid SQL injections.
-         * <p/>
-         * Passed objects will be immediately converted
-         * to list of {@link String} via calling {@link Object#toString()}.
-         * <p/>
-         * Default value is {@code null}.
-         *
-         * @param args arguments fro SQL query.
-         * @return builder.
-         * @see RawQuery#args()
-         */
-        @NonNull
-        public CompleteBuilder args(@NonNull Object... args) {
-            this.args = unmodifiableNonNullListOfStrings(args);
-            return this;
-        }
-
-        /**
-         * Optional: Specifies set of tables which will be affected by this query.
-         * They will be used to notify observers of that tables.
-         * <p/>
-         * Default value is {@code null}.
-         *
-         * @param tables set of tables which will be affected by this query.
-         * @return builder.
-         * @see RawQuery#affectsTables()
-         */
-        @NonNull
-        public CompleteBuilder affectsTables(@NonNull String... tables) {
-            if (this.affectsTables == null) {
-                this.affectsTables = new HashSet<String>(tables.length);
-            }
-
-            Collections.addAll(this.affectsTables, tables);
-            return this;
-        }
-
-        /**
-         * Optional: Specifies set of tables that should be observed by this query.
-         * They will be used to re-execute query if one of the tables will be changed.
-         * <p/>
-         * Default values is {@code null}.
-         *
-         * @param tables set of tables that should be observed by this query.
-         * @return builder.
-         * @see RawQuery#observesTables()
-         */
-        @NonNull
-        public CompleteBuilder observesTables(@NonNull String... tables) {
-            if (this.observesTables == null) {
-                this.observesTables = new HashSet<String>(tables.length);
-            }
-
-            Collections.addAll(this.observesTables, tables);
-            return this;
-        }
-
-        /**
-         * Builds immutable instance of {@link RawQuery}.
-         *
-         * @return immutable instance of {@link RawQuery}.
-         */
-        @NonNull
-        public RawQuery build() {
-            return new RawQuery(
-                    query,
-                    args,
-                    affectsTables,
-                    observesTables
-            );
-        }
-    }
-}
diff --git a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/UpdateQuery.java b/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/UpdateQuery.java
deleted file mode 100644
index 8bdc0fd..0000000
--- a/storio-sqlite/src/main/java/com/pushtorefresh/storio/sqlite/query/UpdateQuery.java
+++ /dev/null
@@ -1,207 +0,0 @@
-package com.pushtorefresh.storio.sqlite.query;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import java.util.List;
-
-import static com.pushtorefresh.storio.internal.Checks.checkNotEmpty;
-import static com.pushtorefresh.storio.internal.Queries.nonNullString;
-import static com.pushtorefresh.storio.internal.Queries.unmodifiableNonNullListOfStrings;
-
-/**
- * Update query for {@link com.pushtorefresh.storio.sqlite.StorIOSQLite}.
- * <p/>
- * Instances of this class are immutable.
- */
-public final class UpdateQuery {
-
-    @NonNull
-    private final String table;
-
-    @NonNull
-    private final String where;
-
-    @NonNull
-    private final List<String> whereArgs;
-
-    /**
-     * Please use {@link com.pushtorefresh.storio.sqlite.query.UpdateQuery.Builder}
-     * instead of constructor.
-     */
-    private UpdateQuery(@NonNull String table, @Nullable String where, @Nullable List<String> whereArgs) {
-        this.table = table;
-        this.where = nonNullString(where);
-        this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
-    }
-
-    /**
-     * Gets table name.
-     *
-     * @return non-null table name.
-     */
-    @NonNull
-    public String table() {
-        return table;
-    }
-
-    /**
-     * Gets {@code WHERE} clause.
-     * <p/>
-     * Optional filter declaring which rows to update.
-     * <p/>
-     * Formatted as an SQL {@code WHERE} clause (excluding the {@code WHERE} itself).
-     * <p/>
-     * If empty — Query will update all rows for the given table.
-     *
-     * @return non-null {@code WHERE} clause.
-     */
-    @NonNull
-    public String where() {
-        return where;
-    }
-
-    /**
-     * Gets optional immutable list of arguments for {@link #where()} clause.
-     *
-     * @return non-null, immutable list of arguments for {@code WHERE} clause.
-     */
-    @NonNull
-    public List<String> whereArgs() {
-        return whereArgs;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        UpdateQuery that = (UpdateQuery) o;
-
-        if (!table.equals(that.table)) return false;
-        if (!where.equals(that.where)) return false;
-        return whereArgs.equals(that.whereArgs);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = table.hashCode();
-        result = 31 * result + where.hashCode();
-        result = 31 * result + whereArgs.hashCode();
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "UpdateQuery{" +
-                "table='" + table + '\'' +
-                ", where='" + where + '\'' +
-                ", whereArgs=" + whereArgs +
-                '}';
-    }
-
-    /**
-     * Creates new builder for {@link UpdateQuery}.
-     *
-     * @return non-null instance of {@link UpdateQuery.Builder}.
-     */
-    @NonNull
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    /**
-     * Builder for {@link UpdateQuery}.
-     */
-    public static final class Builder {
-
-        /**
-         * Please use {@link UpdateQuery#builder()} instead of this.
-         */
-        Builder() {
-        }
-
-        /**
-         * Required: Specifies table name.
-         *
-         * @param table non-null table name.
-         * @return builder.
-         * @see UpdateQuery#table()
-         */
-        @NonNull
-        public CompleteBuilder table(@NonNull String table) {
-            checkNotEmpty(table, "Table name is null or empty");
-            return new CompleteBuilder(table);
-        }
-    }
-
-    /**
-     * Compile-time safe part of builder for {@link DeleteQuery}.
-     */
-    public static final class CompleteBuilder {
-
-        @NonNull
-        private final String table;
-
-        private String where;
-
-        private List<String> whereArgs;
-
-        CompleteBuilder(@NonNull String table) {
-            this.table = table;
-        }
-
-        /**
-         * Optional: Specifies {@code WHERE} clause.
-         * <p/>
-         * Optional filter declaring which rows to return.
-         * <p/>
-         * Formatted as an SQL WHERE clause (excluding the {@code WHERE} itself).
-         * <p/>
-         * Passing {@code null} will UPDATE all rows for the given table.
-         * <p/>
-         * Default value is {@code null}.
-         *
-         * @param where {@code WHERE} clause.
-         * @return builder.
-         * @see UpdateQuery#where()
-         */
-        @NonNull
-        public CompleteBuilder where(@Nullable String where) {
-            this.where = where;
-            return this;
-        }
-
-        /**
-         * Optional: Specifies arguments for {@code WHERE} clause.
-         * <p/>
-         * Passed objects will be immediately converted
-         * to list of {@link String} via calling {@link Object#toString()}.
-         * <p/>
-         * Default value is {@code null}.
-         *
-         * @param whereArgs list of arguments for {@code WHERE} clause.
-         * @return builder.
-         * @see UpdateQuery#whereArgs()
-         */
-        @NonNull
-        public CompleteBuilder whereArgs(@Nullable Object... whereArgs) {
-            this.whereArgs = unmodifiableNonNullListOfStrings(whereArgs);
-            return this;
-        }
-
-        /**
-         * Builds immutable instance of {@link UpdateQuery}.
-         *
-         * @return immutable instance of {@link UpdateQuery}.
-         */
-        @NonNull
-        public UpdateQuery build() {
-            return new UpdateQuery(
-                    table,
-                    where,
-                    whereArgs
-            );
-        }
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/SQLiteTypeMappingTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/SQLiteTypeMappingTest.java
index e9e3d69..01b699a 100644
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/SQLiteTypeMappingTest.java
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/SQLiteTypeMappingTest.java
@@ -1,8 +1,8 @@
 package com.pushtorefresh.storio.sqlite;
 
-import com.pushtorefresh.storio.sqlite.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.sqlite.operation.get.GetResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResolver;
+import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.sqlite.operations.get.GetResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResolver;
 
 import org.junit.Test;
 
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/DeleteOperationDesignTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/DeleteOperationDesignTest.java
index 2e8b097..d14133e 100644
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/DeleteOperationDesignTest.java
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/DeleteOperationDesignTest.java
@@ -1,8 +1,8 @@
 package com.pushtorefresh.storio.sqlite.design;
 
-import com.pushtorefresh.storio.sqlite.operation.delete.DeleteResult;
-import com.pushtorefresh.storio.sqlite.operation.delete.DeleteResults;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
+import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResult;
+import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResults;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
 
 import org.junit.Test;
 
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/DesignTestStorIOSQLite.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/DesignTestStorIOSQLite.java
index be20bf3..41b5aef 100644
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/DesignTestStorIOSQLite.java
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/DesignTestStorIOSQLite.java
@@ -8,15 +8,15 @@
 import com.pushtorefresh.storio.sqlite.Changes;
 import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
 import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.operation.delete.PreparedDelete;
-import com.pushtorefresh.storio.sqlite.operation.execute.PreparedExecuteSQL;
-import com.pushtorefresh.storio.sqlite.operation.get.PreparedGet;
-import com.pushtorefresh.storio.sqlite.operation.put.PreparedPut;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-import com.pushtorefresh.storio.sqlite.query.InsertQuery;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
-import com.pushtorefresh.storio.sqlite.query.UpdateQuery;
+import com.pushtorefresh.storio.sqlite.operations.delete.PreparedDelete;
+import com.pushtorefresh.storio.sqlite.operations.execute.PreparedExecuteSQL;
+import com.pushtorefresh.storio.sqlite.operations.get.PreparedGet;
+import com.pushtorefresh.storio.sqlite.operations.put.PreparedPut;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+import com.pushtorefresh.storio.sqlite.queries.InsertQuery;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
+import com.pushtorefresh.storio.sqlite.queries.UpdateQuery;
 
 import java.io.IOException;
 import java.util.Set;
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/ExecuteSQLOperationDesignTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/ExecuteSQLOperationDesignTest.java
index 0166998..63d1f86 100644
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/ExecuteSQLOperationDesignTest.java
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/ExecuteSQLOperationDesignTest.java
@@ -1,6 +1,6 @@
 package com.pushtorefresh.storio.sqlite.design;
 
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
 
 import org.junit.Test;
 
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/GetOperationDesignTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/GetOperationDesignTest.java
index 43ecc8a..c82f1fa 100644
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/GetOperationDesignTest.java
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/GetOperationDesignTest.java
@@ -2,8 +2,8 @@
 
 import android.database.Cursor;
 
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
 
 import org.junit.Test;
 
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/PutOperationDesignTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/PutOperationDesignTest.java
index 337b96d..01e41dd 100644
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/PutOperationDesignTest.java
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/PutOperationDesignTest.java
@@ -3,12 +3,12 @@
 import android.content.ContentValues;
 import android.support.annotation.NonNull;
 
-import com.pushtorefresh.storio.sqlite.operation.put.DefaultPutResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResult;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResults;
-import com.pushtorefresh.storio.sqlite.query.InsertQuery;
-import com.pushtorefresh.storio.sqlite.query.UpdateQuery;
+import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResult;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResults;
+import com.pushtorefresh.storio.sqlite.queries.InsertQuery;
+import com.pushtorefresh.storio.sqlite.queries.UpdateQuery;
 
 import org.junit.Test;
 
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/UserTableMeta.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/UserTableMeta.java
index e32f178..d502f3e 100644
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/UserTableMeta.java
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/design/UserTableMeta.java
@@ -4,15 +4,15 @@
 import android.database.Cursor;
 import android.support.annotation.NonNull;
 
-import com.pushtorefresh.storio.sqlite.operation.delete.DefaultDeleteResolver;
-import com.pushtorefresh.storio.sqlite.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.sqlite.operation.get.DefaultGetResolver;
-import com.pushtorefresh.storio.sqlite.operation.get.GetResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.DefaultPutResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResolver;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-import com.pushtorefresh.storio.sqlite.query.InsertQuery;
-import com.pushtorefresh.storio.sqlite.query.UpdateQuery;
+import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver;
+import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver;
+import com.pushtorefresh.storio.sqlite.operations.get.GetResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResolver;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+import com.pushtorefresh.storio.sqlite.queries.InsertQuery;
+import com.pushtorefresh.storio.sqlite.queries.UpdateQuery;
 
 import static org.mockito.Mockito.mock;
 
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/impl/DefaultStorIOSQLiteTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/impl/DefaultStorIOSQLiteTest.java
index cf0101e..09751ca 100644
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/impl/DefaultStorIOSQLiteTest.java
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/impl/DefaultStorIOSQLiteTest.java
@@ -4,9 +4,9 @@
 
 import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
 import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.sqlite.operation.get.GetResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResolver;
+import com.pushtorefresh.storio.sqlite.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.sqlite.operations.get.GetResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResolver;
 
 import org.junit.Test;
 
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DefaultDeleteResolverTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DefaultDeleteResolverTest.java
deleted file mode 100644
index ba5aabf..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DefaultDeleteResolverTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-
-import org.junit.Test;
-
-import java.util.Collections;
-
-import static junit.framework.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class DefaultDeleteResolverTest {
-
-    @Test
-    public void performDelete() {
-        final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-        final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-        final String testTable = "test_table";
-        final DeleteQuery deleteQuery = DeleteQuery.builder()
-                .table(testTable)
-                .build();
-
-        when(storIOSQLite.internal())
-                .thenReturn(internal);
-
-        when(internal.delete(deleteQuery))
-                .thenReturn(1);
-
-        final TestItem testItem = new TestItem();
-
-        final DefaultDeleteResolver<TestItem> defaultDeleteResolver = new DefaultDeleteResolver<TestItem>() {
-            @NonNull
-            @Override
-            public DeleteQuery mapToDeleteQuery(@NonNull TestItem testItem) {
-                return deleteQuery;
-            }
-        };
-
-        final DeleteResult deleteResult = defaultDeleteResolver.performDelete(storIOSQLite, testItem);
-
-        verify(internal, times(1)).delete(any(DeleteQuery.class));
-        verify(internal, times(1)).delete(deleteQuery);
-
-        assertEquals(1, deleteResult.numberOfRowsDeleted());
-        assertEquals(Collections.singleton(testTable), deleteResult.affectedTables());
-    }
-
-    private static class TestItem {
-
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResultTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResultTest.java
deleted file mode 100644
index 002bd24..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResultTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import org.junit.Test;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-import static org.junit.Assert.assertEquals;
-
-public class DeleteResultTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void nullAffectedTable() {
-        DeleteResult.newInstance(0, (String) null);
-    }
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void nullAffectedTables() {
-        DeleteResult.newInstance(0, (Set<String>) null);
-    }
-
-    @Test
-    public void numberOfRowsDeleted() {
-        final DeleteResult deleteResult = DeleteResult.newInstance(3, "test_table");
-        assertEquals(3, deleteResult.numberOfRowsDeleted());
-    }
-
-    @Test
-    public void oneAffectedTable() {
-        final DeleteResult deleteResult = DeleteResult.newInstance(2, "test_table");
-        assertEquals(Collections.singleton("test_table"), deleteResult.affectedTables());
-    }
-
-    @Test
-    public void multipleAffectedTables() {
-        final Set<String> affectedTables = new HashSet<String>();
-        affectedTables.add("table1");
-        affectedTables.add("table2");
-
-        final DeleteResult deleteResult = DeleteResult.newInstance(2, affectedTables);
-
-        assertEquals(affectedTables, deleteResult.affectedTables());
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResultsTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResultsTest.java
deleted file mode 100644
index 12fadc0..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteResultsTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class DeleteResultsTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void nullResults() {
-        DeleteResults.newInstance(null);
-    }
-
-    @Test
-    public void results() {
-        final Map<Object, DeleteResult> results = new HashMap<Object, DeleteResult>();
-        final DeleteResults<Object> deleteResults = DeleteResults.newInstance(results);
-        assertEquals(results, deleteResults.results());
-    }
-
-    @Test
-    public void wasDeleted() {
-        final Map<String, DeleteResult> results = new HashMap<String, DeleteResult>();
-        results.put("testString", DeleteResult.newInstance(1, "test_table"));
-
-        final DeleteResults<String> deleteResults = DeleteResults.newInstance(results);
-
-        assertTrue(deleteResults.wasDeleted("testString"));
-        assertFalse(deleteResults.wasDeleted("should not be deleted"));
-
-        assertFalse(deleteResults.wasNotDeleted("testString"));
-        assertTrue(deleteResults.wasNotDeleted("should not be deleted"));
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteStub.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteStub.java
deleted file mode 100644
index 4b9feab..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/DeleteStub.java
+++ /dev/null
@@ -1,176 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.sqlite.Changes;
-import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import rx.Observable;
-import rx.functions.Action1;
-
-import static java.util.Collections.singletonMap;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@SuppressWarnings("unchecked")
-class DeleteStub {
-
-    @NonNull
-    final StorIOSQLite storIOSQLite;
-
-    @NonNull
-    private final StorIOSQLite.Internal internal;
-
-    @NonNull
-    final List<TestItem> items;
-
-    @NonNull
-    final DeleteResolver<TestItem> deleteResolver;
-
-    @NonNull
-    private final SQLiteTypeMapping<TestItem> typeMapping;
-
-    private final boolean withTypeMapping, useTransaction;
-
-    private DeleteStub(boolean withTypeMapping, boolean useTransaction, int numberOfItems) {
-        this.withTypeMapping = withTypeMapping;
-        this.useTransaction = useTransaction;
-
-        storIOSQLite = mock(StorIOSQLite.class);
-        internal = mock(StorIOSQLite.Internal.class);
-
-        items = new ArrayList<TestItem>(numberOfItems);
-
-        for (int i = 0; i < numberOfItems; i++) {
-            items.add(TestItem.newInstance());
-        }
-
-        deleteResolver = mock(DeleteResolver.class);
-
-        typeMapping = mock(SQLiteTypeMapping.class);
-
-        when(storIOSQLite.internal()).thenReturn(internal);
-        when(storIOSQLite.delete()).thenReturn(new PreparedDelete.Builder(storIOSQLite));
-        when(deleteResolver.performDelete(eq(storIOSQLite), any(TestItem.class)))
-                .thenReturn(DeleteResult.newInstance(1, TestItem.TABLE));
-
-        if (withTypeMapping) {
-            when(internal.typeMapping(TestItem.class)).thenReturn(typeMapping);
-            when(typeMapping.deleteResolver()).thenReturn(deleteResolver);
-        }
-    }
-
-    @NonNull
-    static DeleteStub newStubForMultipleObjectsWithoutTypeMappingWithoutTransaction() {
-        return new DeleteStub(false, false, 3);
-    }
-
-    @NonNull
-    static DeleteStub newStubForMultipleObjectsWithoutTypeMappingWithTransaction() {
-        return new DeleteStub(false, true, 3);
-    }
-
-    @NonNull
-    static DeleteStub newStubForMultipleObjectsWithTypeMappingWithoutTransaction() {
-        return new DeleteStub(true, false, 3);
-    }
-
-    @NonNull
-    static DeleteStub newStubForMultipleObjectsWithTypeMappingWithTransaction() {
-        return new DeleteStub(true, true, 3);
-    }
-
-    @NonNull
-    static DeleteStub newStubForOneObjectWithoutTypeMapping() {
-        return new DeleteStub(false, false, 1);
-    }
-
-    @NonNull
-    static DeleteStub newStubForOneObjectWithTypeMapping() {
-        return new DeleteStub(true, false, 1);
-    }
-
-    void verifyBehaviorForMultipleObjects(@NonNull DeleteResults<TestItem> deleteResults) {
-        verify(storIOSQLite).delete(); // Only one call to delete should occur
-
-        verify(storIOSQLite).internal(); // Only one call to internal should occur
-
-        // Number of calls to perform deletion of objects should be equals to number of items
-        verify(deleteResolver, times(items.size()))
-                .performDelete(eq(storIOSQLite), any(TestItem.class));
-
-        // Perform delete should be called for each item
-        for (TestItem item : items) {
-            verify(deleteResolver).performDelete(storIOSQLite, item);
-        }
-
-        if (withTypeMapping) {
-            // Number of calls to receive delete resolver should be equal to number of items
-            verify(internal, times(items.size())).typeMapping(TestItem.class);
-            verify(typeMapping, times(items.size())).deleteResolver();
-        }
-
-        verifyTransactionBehavior();
-        verifyNoMoreInteractions(storIOSQLite, internal, deleteResolver, typeMapping);
-    }
-
-    void verifyBehaviorForMultipleObjects(@NonNull Observable<DeleteResults<TestItem>> observable) {
-        new ObservableBehaviorChecker<DeleteResults<TestItem>>()
-                .observable(observable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<DeleteResults<TestItem>>() {
-                    @Override
-                    public void call(DeleteResults<TestItem> deleteResults) {
-                        verifyBehaviorForMultipleObjects(deleteResults);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-
-    void verifyBehaviorForOneObject(@NonNull DeleteResult deleteResult) {
-        verifyBehaviorForMultipleObjects(DeleteResults.newInstance(singletonMap(items.get(0), deleteResult)));
-    }
-
-    void verifyBehaviorForOneObject(@NonNull Observable<DeleteResult> observable) {
-        new ObservableBehaviorChecker<DeleteResult>()
-                .observable(observable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<DeleteResult>() {
-                    @Override
-                    public void call(DeleteResult deleteResult) {
-                        verifyBehaviorForOneObject(deleteResult);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-
-    private void verifyTransactionBehavior() {
-        if (useTransaction) {
-            verify(internal).beginTransaction();
-            verify(internal).setTransactionSuccessful();
-            verify(internal).endTransaction();
-
-            // Only one notification should be thrown
-            verify(internal).notifyAboutChanges(eq(Changes.newInstance(TestItem.TABLE)));
-        } else {
-            verify(internal, never()).beginTransaction();
-            verify(internal, never()).setTransactionSuccessful();
-            verify(internal, never()).endTransaction();
-
-            // Each delete should trigger notification
-            verify(internal, times(items.size()))
-                    .notifyAboutChanges(eq(Changes.newInstance(TestItem.TABLE)));
-        }
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteCollectionOfObjectsTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteCollectionOfObjectsTest.java
deleted file mode 100644
index 6ac3453..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteCollectionOfObjectsTest.java
+++ /dev/null
@@ -1,285 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-
-import org.junit.Test;
-import org.junit.experimental.runners.Enclosed;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-import rx.Observable;
-import rx.observers.TestSubscriber;
-
-import static java.util.Arrays.asList;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(Enclosed.class)
-public class PreparedDeleteCollectionOfObjectsTest {
-
-    public static class WithoutTypeMapping {
-
-        @Test
-        public void shouldDeleteObjectsWithoutTypeMappingWithoutTransactionBlocking() {
-            final DeleteStub deleteStub
-                    = DeleteStub.newStubForMultipleObjectsWithoutTypeMappingWithoutTransaction();
-
-            final DeleteResults<TestItem> deleteResults = deleteStub.storIOSQLite
-                    .delete()
-                    .objects(deleteStub.items)
-                    .useTransaction(false)
-                    .withDeleteResolver(deleteStub.deleteResolver)
-                    .prepare()
-                    .executeAsBlocking();
-
-            deleteStub.verifyBehaviorForMultipleObjects(deleteResults);
-        }
-
-        @Test
-        public void shouldDeleteObjectsWithoutTypeMappingWithTransactionBlocking() {
-            final DeleteStub deleteStub
-                    = DeleteStub.newStubForMultipleObjectsWithoutTypeMappingWithTransaction();
-
-            final DeleteResults<TestItem> deleteResults = deleteStub.storIOSQLite
-                    .delete()
-                    .objects(deleteStub.items)
-                    .useTransaction(true)
-                    .withDeleteResolver(deleteStub.deleteResolver)
-                    .prepare()
-                    .executeAsBlocking();
-
-            deleteStub.verifyBehaviorForMultipleObjects(deleteResults);
-        }
-
-        @Test
-        public void shouldDeleteObjectsWithoutTypeMappingWithoutTransactionAsObservable() {
-            final DeleteStub deleteStub
-                    = DeleteStub.newStubForMultipleObjectsWithoutTypeMappingWithoutTransaction();
-
-            final Observable<DeleteResults<TestItem>> observable = deleteStub.storIOSQLite
-                    .delete()
-                    .objects(deleteStub.items)
-                    .useTransaction(false)
-                    .withDeleteResolver(deleteStub.deleteResolver)
-                    .prepare()
-                    .createObservable();
-
-            deleteStub.verifyBehaviorForMultipleObjects(observable);
-        }
-
-        @Test
-        public void shouldDeleteObjectsWithoutTypeMappingWithTransactionAsObservable() {
-            final DeleteStub deleteStub
-                    = DeleteStub.newStubForMultipleObjectsWithoutTypeMappingWithTransaction();
-
-            final Observable<DeleteResults<TestItem>> observable = deleteStub.storIOSQLite
-                    .delete()
-                    .objects(deleteStub.items)
-                    .useTransaction(true)
-                    .withDeleteResolver(deleteStub.deleteResolver)
-                    .prepare()
-                    .createObservable();
-
-            deleteStub.verifyBehaviorForMultipleObjects(observable);
-        }
-    }
-
-    public static class WithTypeMapping {
-
-        @Test
-        public void shouldDeleteObjectsWithTypeMappingWithoutTransactionBlocking() {
-            final DeleteStub deleteStub
-                    = DeleteStub.newStubForMultipleObjectsWithTypeMappingWithoutTransaction();
-
-            final DeleteResults<TestItem> deleteResults = deleteStub.storIOSQLite
-                    .delete()
-                    .objects(deleteStub.items)
-                    .useTransaction(false)
-                    .prepare()
-                    .executeAsBlocking();
-
-            deleteStub.verifyBehaviorForMultipleObjects(deleteResults);
-        }
-
-        @Test
-        public void shouldDeleteObjectsWithTypeMappingWithTransactionBlocking() {
-            final DeleteStub deleteStub
-                    = DeleteStub.newStubForMultipleObjectsWithTypeMappingWithTransaction();
-
-            final DeleteResults<TestItem> deleteResults = deleteStub.storIOSQLite
-                    .delete()
-                    .objects(deleteStub.items)
-                    .useTransaction(true)
-                    .prepare()
-                    .executeAsBlocking();
-
-            deleteStub.verifyBehaviorForMultipleObjects(deleteResults);
-        }
-
-        @Test
-        public void shouldDeleteObjectsWithTypeMappingWithoutTransactionObservable() {
-            final DeleteStub deleteStub
-                    = DeleteStub.newStubForMultipleObjectsWithTypeMappingWithoutTransaction();
-
-            final Observable<DeleteResults<TestItem>> observable = deleteStub.storIOSQLite
-                    .delete()
-                    .objects(deleteStub.items)
-                    .useTransaction(false)
-                    .prepare()
-                    .createObservable();
-
-            deleteStub.verifyBehaviorForMultipleObjects(observable);
-        }
-
-        @Test
-        public void shouldDeleteObjectsWithTypeMappingWithTransactionObservable() {
-            final DeleteStub deleteStub
-                    = DeleteStub.newStubForMultipleObjectsWithTypeMappingWithTransaction();
-
-            final Observable<DeleteResults<TestItem>> observable = deleteStub.storIOSQLite
-                    .delete()
-                    .objects(deleteStub.items)
-                    .useTransaction(true)
-                    .prepare()
-                    .createObservable();
-
-            deleteStub.verifyBehaviorForMultipleObjects(observable);
-        }
-    }
-
-    public static class NoTypeMappingError {
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutTransactionWithoutAffectingDbBlocking() {
-            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-            when(storIOSQLite.internal()).thenReturn(internal);
-
-            when(storIOSQLite.delete()).thenReturn(new PreparedDelete.Builder(storIOSQLite));
-
-            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
-
-            final PreparedDelete<DeleteResults<TestItem>> preparedDelete = storIOSQLite
-                    .delete()
-                    .objects(items)
-                    .useTransaction(false)
-                    .prepare();
-
-            try {
-                preparedDelete.executeAsBlocking();
-                fail();
-            } catch (IllegalStateException expected) {
-                // it's okay, no type mapping was found
-            }
-
-            verify(storIOSQLite).delete();
-            verify(storIOSQLite).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).delete(any(DeleteQuery.class));
-            verifyNoMoreInteractions(storIOSQLite, internal);
-        }
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutTransactionWithoutAffectingDbAsObservable() {
-            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-            when(storIOSQLite.internal()).thenReturn(internal);
-
-            when(storIOSQLite.delete()).thenReturn(new PreparedDelete.Builder(storIOSQLite));
-
-            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
-
-            final TestSubscriber<DeleteResults<TestItem>> testSubscriber = new TestSubscriber<DeleteResults<TestItem>>();
-
-            storIOSQLite
-                    .delete()
-                    .objects(items)
-                    .useTransaction(false)
-                    .prepare()
-                    .createObservable()
-                    .subscribe(testSubscriber);
-
-            testSubscriber.awaitTerminalEvent();
-            testSubscriber.assertNoValues();
-            testSubscriber.assertError(IllegalStateException.class);
-
-            verify(storIOSQLite).delete();
-            verify(storIOSQLite).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).delete(any(DeleteQuery.class));
-            verifyNoMoreInteractions(storIOSQLite, internal);
-        }
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithTransactionWithoutAffectingDbBlocking() {
-            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-            when(storIOSQLite.internal()).thenReturn(internal);
-
-            when(storIOSQLite.delete()).thenReturn(new PreparedDelete.Builder(storIOSQLite));
-
-            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
-
-            final PreparedDelete<DeleteResults<TestItem>> preparedDelete = storIOSQLite
-                    .delete()
-                    .objects(items)
-                    .useTransaction(true)
-                    .prepare();
-
-            try {
-                preparedDelete.executeAsBlocking();
-                fail();
-            } catch (IllegalStateException expected) {
-                // it's okay, no type mapping was found
-            }
-
-            verify(storIOSQLite).delete();
-            verify(storIOSQLite).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).delete(any(DeleteQuery.class));
-            verifyNoMoreInteractions(storIOSQLite, internal);
-        }
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithTransactionWithoutAffectingDbAsObservable() {
-            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-            when(storIOSQLite.internal()).thenReturn(internal);
-
-            when(storIOSQLite.delete()).thenReturn(new PreparedDelete.Builder(storIOSQLite));
-
-            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
-
-            final TestSubscriber<DeleteResults<TestItem>> testSubscriber = new TestSubscriber<DeleteResults<TestItem>>();
-
-            storIOSQLite
-                    .delete()
-                    .objects(items)
-                    .useTransaction(true)
-                    .prepare()
-                    .createObservable()
-                    .subscribe(testSubscriber);
-
-            testSubscriber.awaitTerminalEvent();
-            testSubscriber.assertNoValues();
-            testSubscriber.assertError(IllegalStateException.class);
-
-            verify(storIOSQLite).delete();
-            verify(storIOSQLite).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).delete(any(DeleteQuery.class));
-            verifyNoMoreInteractions(storIOSQLite, internal);
-        }
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteObjectTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteObjectTest.java
deleted file mode 100644
index a5d5c49..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/PreparedDeleteObjectTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.DeleteQuery;
-
-import org.junit.Test;
-import org.junit.experimental.runners.Enclosed;
-import org.junit.runner.RunWith;
-
-import rx.Observable;
-import rx.observers.TestSubscriber;
-
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(Enclosed.class)
-public class PreparedDeleteObjectTest {
-
-    public static class WithoutTypeMapping {
-
-        @Test
-        public void shouldDeleteObjectWithoutTypeMappingBlocking() {
-            final DeleteStub deleteStub = DeleteStub.newStubForOneObjectWithoutTypeMapping();
-
-            final DeleteResult deleteResult = deleteStub.storIOSQLite
-                    .delete()
-                    .object(deleteStub.items.get(0))
-                    .withDeleteResolver(deleteStub.deleteResolver)
-                    .prepare()
-                    .executeAsBlocking();
-
-            deleteStub.verifyBehaviorForOneObject(deleteResult);
-        }
-
-        @Test
-        public void shouldDeleteObjectWithoutTypeMappingAsObservable() {
-            final DeleteStub deleteStub = DeleteStub.newStubForOneObjectWithoutTypeMapping();
-
-            final Observable<DeleteResult> observable = deleteStub.storIOSQLite
-                    .delete()
-                    .object(deleteStub.items.get(0))
-                    .withDeleteResolver(deleteStub.deleteResolver)
-                    .prepare()
-                    .createObservable();
-
-            deleteStub.verifyBehaviorForOneObject(observable);
-        }
-    }
-
-    public static class WithTypeMapping {
-
-        @Test
-        public void shouldDeleteObjectWithTypeMappingBlocking() {
-            final DeleteStub deleteStub = DeleteStub.newStubForOneObjectWithTypeMapping();
-
-            final DeleteResult deleteResult = deleteStub.storIOSQLite
-                    .delete()
-                    .object(deleteStub.items.get(0))
-                    .prepare()
-                    .executeAsBlocking();
-
-            deleteStub.verifyBehaviorForOneObject(deleteResult);
-        }
-
-        @Test
-        public void shouldDeleteObjectWithTypeMappingAsObservable() {
-            final DeleteStub deleteStub = DeleteStub.newStubForOneObjectWithTypeMapping();
-
-            final Observable<DeleteResult> observable = deleteStub.storIOSQLite
-                    .delete()
-                    .object(deleteStub.items.get(0))
-                    .prepare()
-                    .createObservable();
-
-            deleteStub.verifyBehaviorForOneObject(observable);
-        }
-    }
-
-    public static class NoTypeMappingError {
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingDbBlocking() {
-            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-            when(storIOSQLite.internal()).thenReturn(internal);
-
-            when(storIOSQLite.delete()).thenReturn(new PreparedDelete.Builder(storIOSQLite));
-
-            final PreparedDelete<DeleteResult> preparedDelete = storIOSQLite
-                    .delete()
-                    .object(TestItem.newInstance())
-                    .prepare();
-
-            try {
-                preparedDelete.executeAsBlocking();
-                fail();
-            } catch (IllegalStateException expected) {
-                // it's okay, no type mapping was found
-            }
-
-            verify(storIOSQLite).delete();
-            verify(storIOSQLite).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).delete(any(DeleteQuery.class));
-            verifyNoMoreInteractions(storIOSQLite, internal);
-        }
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingDbAsObservable() {
-            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-            when(storIOSQLite.internal()).thenReturn(internal);
-
-            when(storIOSQLite.delete()).thenReturn(new PreparedDelete.Builder(storIOSQLite));
-
-            final TestSubscriber<DeleteResult> testSubscriber = new TestSubscriber<DeleteResult>();
-
-            storIOSQLite
-                    .delete()
-                    .object(TestItem.newInstance())
-                    .prepare()
-                    .createObservable()
-                    .subscribe(testSubscriber);
-
-            testSubscriber.awaitTerminalEvent();
-            testSubscriber.assertNoValues();
-            testSubscriber.assertError(IllegalStateException.class);
-
-            verify(storIOSQLite).delete();
-            verify(storIOSQLite).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).delete(any(DeleteQuery.class));
-            verifyNoMoreInteractions(storIOSQLite, internal);
-        }
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/TestItem.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/TestItem.java
deleted file mode 100644
index c0747e2..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/delete/TestItem.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.delete;
-
-import android.support.annotation.NonNull;
-
-class TestItem {
-
-    static final String TABLE = "test_items";
-
-    private TestItem() {
-
-    }
-
-    @NonNull
-    static TestItem newInstance() {
-        return new TestItem();
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/execute/PreparedExecuteSQLTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/execute/PreparedExecuteSQLTest.java
deleted file mode 100644
index ff6e1ee..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/execute/PreparedExecuteSQLTest.java
+++ /dev/null
@@ -1,153 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.execute;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.sqlite.Changes;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
-import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
-
-import org.junit.Test;
-
-import java.util.HashSet;
-
-import rx.Observable;
-import rx.functions.Action1;
-
-import static java.util.Arrays.asList;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class PreparedExecuteSQLTest {
-
-    @Test
-    public void executeSQLBlockingWithoutNotifications() {
-        final Stub stub = Stub.newInstanceWithoutNotification();
-
-        stub.storIOSQLite
-                .executeSQL()
-                .withQuery(stub.rawQuery)
-                .prepare()
-                .executeAsBlocking();
-
-        stub.verifyBehavior();
-    }
-
-    @Test
-    public void executeSQLBlockingWithNotification() {
-        final Stub stub = Stub.newInstanceWithNotification();
-
-        stub.storIOSQLite
-                .executeSQL()
-                .withQuery(stub.rawQuery)
-                .prepare()
-                .executeAsBlocking();
-
-        stub.verifyBehavior();
-    }
-
-    @Test
-    public void executeSQLObservableWithoutNotifications() {
-        final Stub stub = Stub.newInstanceWithoutNotification();
-
-        final Observable<Object> observable = stub.storIOSQLite
-                .executeSQL()
-                .withQuery(stub.rawQuery)
-                .prepare()
-                .createObservable();
-
-        stub.verifyBehavior(observable);
-    }
-
-    @Test
-    public void executeSQLObservableWithNotification() {
-        final Stub stub = Stub.newInstanceWithNotification();
-
-        final Observable<Object> observable = stub.storIOSQLite
-                .executeSQL()
-                .withQuery(stub.rawQuery)
-                .prepare()
-                .createObservable();
-
-        stub.verifyBehavior(observable);
-    }
-
-    static class Stub {
-
-        private final StorIOSQLite storIOSQLite;
-        private final StorIOSQLite.Internal internal;
-        private final RawQuery rawQuery;
-        private final boolean queryWithNotification;
-
-        private final String[] affectedTables = {"test_table1", "test_table2"};
-
-        @NonNull
-        public static Stub newInstanceWithoutNotification() {
-            return new Stub(false);
-        }
-
-        @NonNull
-        public static Stub newInstanceWithNotification() {
-            return new Stub(true);
-        }
-
-        private Stub(boolean queryWithNotification) {
-            this.queryWithNotification = queryWithNotification;
-
-            storIOSQLite = mock(StorIOSQLite.class);
-            internal = mock(StorIOSQLite.Internal.class);
-
-            if (queryWithNotification) {
-                rawQuery = RawQuery.builder()
-                        .query("DROP TABLE users!")
-                        .affectsTables(affectedTables)
-                        .build();
-            } else {
-                rawQuery = RawQuery.builder()
-                        .query("DROP TABLE users!")
-                        .build();
-            }
-
-            when(storIOSQLite.internal())
-                    .thenReturn(internal);
-
-            when(storIOSQLite.executeSQL())
-                    .thenReturn(new PreparedExecuteSQL.Builder(storIOSQLite));
-        }
-
-        @SuppressWarnings("unchecked")
-        void verifyBehavior() {
-            // storIOSQLite.executeSQL() should be called once
-            verify(storIOSQLite, times(1)).executeSQL();
-
-            // storIOSQLite.internal.executeSQL() should be called once for ANY RawQuery
-            verify(internal, times(1)).executeSQL(any(RawQuery.class));
-
-            // storIOSQLite.internal.executeSQL() should be called once for required RawQuery
-            verify(internal, times(1)).executeSQL(rawQuery);
-
-            if (queryWithNotification) {
-                verify(internal).notifyAboutChanges(eq(Changes.newInstance(new HashSet<String>(asList(affectedTables)))));
-            } else {
-                verify(internal, times(0)).notifyAboutChanges(any(Changes.class));
-            }
-        }
-
-        void verifyBehavior(@NonNull Observable<Object> observable) {
-            new ObservableBehaviorChecker<Object>()
-                    .observable(observable)
-                    .expectedNumberOfEmissions(1)
-                    .testAction(new Action1<Object>() {
-                        @Override
-                        public void call(Object anObject) {
-                            verifyBehavior();
-                        }
-                    })
-                    .checkBehaviorOfObservable();
-        }
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/DefaultGetResolverTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/DefaultGetResolverTest.java
deleted file mode 100644
index 632d038..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/DefaultGetResolverTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.get;
-
-import android.database.Cursor;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
-
-import org.junit.Test;
-
-import static junit.framework.Assert.assertSame;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class DefaultGetResolverTest {
-
-    @Test
-    public void rawQuery() {
-        final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-        final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-        final RawQuery rawQuery = RawQuery.builder()
-                .query("test sql")
-                .build();
-
-        final Cursor expectedCursor = mock(Cursor.class);
-
-        when(storIOSQLite.internal())
-                .thenReturn(internal);
-
-        when(internal.rawQuery(rawQuery))
-                .thenReturn(expectedCursor);
-
-        final DefaultGetResolver<TestItem> defaultGetResolver = new DefaultGetResolver<TestItem>() {
-            @NonNull
-            @Override
-            public TestItem mapFromCursor(@NonNull Cursor cursor) {
-                return mock(TestItem.class);
-            }
-        };
-
-        final Cursor actualCursor = defaultGetResolver.performGet(storIOSQLite, rawQuery);
-
-        // only one request should occur
-        verify(internal, times(1)).rawQuery(any(RawQuery.class));
-
-        // and this request should be equals to original
-        verify(internal, times(1)).rawQuery(rawQuery);
-
-        assertSame(expectedCursor, actualCursor);
-    }
-
-    @Test
-    public void query() {
-        final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-        final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-        final Query query = Query.builder()
-                .table("test_table")
-                .build();
-
-        final Cursor expectedCursor = mock(Cursor.class);
-
-        when(storIOSQLite.internal())
-                .thenReturn(internal);
-
-        when(internal.query(query))
-                .thenReturn(expectedCursor);
-
-        final DefaultGetResolver<TestItem> defaultGetResolver = new DefaultGetResolver<TestItem>() {
-            @NonNull
-            @Override
-            public TestItem mapFromCursor(@NonNull Cursor cursor) {
-                return mock(TestItem.class);
-            }
-        };
-
-        final Cursor actualCursor = defaultGetResolver.performGet(storIOSQLite, query);
-
-        // only one request should occur
-        verify(internal, times(1)).query(any(Query.class));
-
-        // and this request should be equals to original
-        verify(internal, times(1)).query(query);
-
-        assertSame(expectedCursor, actualCursor);
-    }
-
-    private static class TestItem {
-
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/GetCursorStub.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/GetCursorStub.java
deleted file mode 100644
index ff3c1c0..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/GetCursorStub.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.get;
-
-import android.database.Cursor;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.sqlite.Changes;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
-import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
-
-import rx.Observable;
-import rx.functions.Action1;
-
-import static java.util.Collections.singleton;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertSame;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-class GetCursorStub {
-
-    @NonNull
-    final StorIOSQLite storIOSQLite;
-
-    @NonNull
-    private final StorIOSQLite.Internal internal;
-
-    @NonNull
-    final Query query;
-
-    @NonNull
-    final RawQuery rawQuery;
-
-    @NonNull
-    final GetResolver<Cursor> getResolverForCursor;
-
-    @NonNull
-    private final Cursor cursor;
-
-    @SuppressWarnings("unchecked")
-    private GetCursorStub() {
-        storIOSQLite = mock(StorIOSQLite.class);
-        internal = mock(StorIOSQLite.Internal.class);
-
-        when(storIOSQLite.internal())
-                .thenReturn(internal);
-
-        query = mock(Query.class);
-        when(query.table()).thenReturn("test_table");
-
-        rawQuery = mock(RawQuery.class);
-        when(rawQuery.observesTables()).thenReturn(singleton("test_table"));
-
-        getResolverForCursor = mock(GetResolver.class);
-        cursor = mock(Cursor.class);
-
-        when(storIOSQLite.get())
-                .thenReturn(new PreparedGet.Builder(storIOSQLite));
-
-        when(storIOSQLite.observeChangesInTables(eq(singleton(query.table()))))
-                .thenReturn(Observable.<Changes>empty());
-
-        assertNotNull(rawQuery.observesTables());
-
-        when(storIOSQLite.observeChangesInTables(rawQuery.observesTables()))
-                .thenReturn(Observable.<Changes>empty());
-
-        when(getResolverForCursor.performGet(storIOSQLite, query))
-                .thenReturn(cursor);
-
-        when(getResolverForCursor.performGet(storIOSQLite, rawQuery))
-                .thenReturn(cursor);
-    }
-
-    @NonNull
-    static GetCursorStub newInstance() {
-        return new GetCursorStub();
-    }
-
-    void verifyQueryBehaviorForCursor(@NonNull Cursor actualCursor) {
-        assertNotNull(actualCursor);
-        verify(storIOSQLite).get();
-        verify(getResolverForCursor).performGet(storIOSQLite, query);
-        assertSame(cursor, actualCursor);
-        verifyNoMoreInteractions(storIOSQLite, internal, cursor);
-    }
-
-    void verifyQueryBehaviorForCursor(@NonNull Observable<Cursor> observable) {
-        new ObservableBehaviorChecker<Cursor>()
-                .observable(observable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<Cursor>() {
-                    @Override
-                    public void call(Cursor cursor) {
-                        // Get Operation should be subscribed to changes of tables from Query
-                        verify(storIOSQLite).observeChangesInTables(eq(singleton(query.table())));
-                        verifyQueryBehaviorForCursor(cursor);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-
-    void verifyRawQueryBehaviorForCursor(@NonNull Cursor actualCursor) {
-        assertNotNull(actualCursor);
-        verify(storIOSQLite, times(1)).get();
-        verify(getResolverForCursor, times(1)).performGet(storIOSQLite, rawQuery);
-        assertSame(cursor, actualCursor);
-        verifyNoMoreInteractions(storIOSQLite, internal, cursor);
-    }
-
-    void verifyRawQueryBehaviorForCursor(@NonNull Observable<Cursor> observable) {
-        new ObservableBehaviorChecker<Cursor>()
-                .observable(observable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<Cursor>() {
-                    @Override
-                    public void call(Cursor cursor) {
-                        // Get Operation should be subscribed to changes of tables from Query
-                        verify(storIOSQLite).observeChangesInTables(rawQuery.observesTables());
-                        verifyRawQueryBehaviorForCursor(cursor);
-                    }
-                })
-                .checkBehaviorOfObservable();
-
-        assertNotNull(rawQuery.observesTables());
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/GetObjectsStub.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/GetObjectsStub.java
deleted file mode 100644
index 35d5d6f..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/GetObjectsStub.java
+++ /dev/null
@@ -1,226 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.get;
-
-import android.database.Cursor;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.sqlite.Changes;
-import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
-import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
-
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import rx.Observable;
-import rx.functions.Action1;
-
-import static com.pushtorefresh.storio.test.Asserts.assertThatListIsImmutable;
-import static java.util.Collections.singleton;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-class GetObjectsStub {
-
-    @NonNull
-    final StorIOSQLite storIOSQLite;
-
-    @NonNull
-    private final StorIOSQLite.Internal internal;
-
-    @NonNull
-    final Query query;
-
-    @NonNull
-    final RawQuery rawQuery;
-
-    @NonNull
-    final GetResolver<TestItem> getResolver;
-
-    @NonNull
-    private final Cursor cursor;
-
-    @NonNull
-    final List<TestItem> items;
-
-    @NonNull
-    private final SQLiteTypeMapping<TestItem> typeMapping;
-
-    private final boolean withTypeMapping;
-
-    @SuppressWarnings("unchecked")
-    private GetObjectsStub(boolean withTypeMapping) {
-        this.withTypeMapping = withTypeMapping;
-
-        storIOSQLite = mock(StorIOSQLite.class);
-        internal = mock(StorIOSQLite.Internal.class);
-
-        when(storIOSQLite.internal())
-                .thenReturn(internal);
-
-        query = mock(Query.class);
-        when(query.table()).thenReturn("test_table");
-
-        rawQuery = mock(RawQuery.class);
-        when(rawQuery.observesTables()).thenReturn(singleton("test_table"));
-
-        getResolver = mock(GetResolver.class);
-        cursor = mock(Cursor.class);
-
-        items = new ArrayList<TestItem>();
-        items.add(new TestItem());
-        items.add(new TestItem());
-        items.add(new TestItem());
-
-        when(cursor.getCount())
-                .thenReturn(items.size());
-
-        when(cursor.moveToNext()).thenAnswer(new Answer<Boolean>() {
-            int invocationsCount = 0;
-
-            @Override
-            public Boolean answer(InvocationOnMock invocation) throws Throwable {
-                return invocationsCount++ < items.size();
-            }
-        });
-
-        when(storIOSQLite.get())
-                .thenReturn(new PreparedGet.Builder(storIOSQLite));
-
-        when(storIOSQLite.observeChangesInTables(eq(singleton(query.table()))))
-                .thenReturn(Observable.<Changes>empty());
-
-        assertNotNull(rawQuery.observesTables());
-
-        when(storIOSQLite.observeChangesInTables(rawQuery.observesTables()))
-                .thenReturn(Observable.<Changes>empty());
-
-        when(getResolver.performGet(storIOSQLite, query))
-                .thenReturn(cursor);
-
-        when(getResolver.performGet(storIOSQLite, rawQuery))
-                .thenReturn(cursor);
-
-        when(getResolver.mapFromCursor(cursor))
-                .thenAnswer(new Answer<TestItem>() {
-                    int invocationsCount = 0;
-
-                    @Override
-                    public TestItem answer(InvocationOnMock invocation) throws Throwable {
-                        final TestItem testItem = items.get(invocationsCount);
-                        invocationsCount++;
-                        return testItem;
-                    }
-                });
-
-        typeMapping = mock(SQLiteTypeMapping.class);
-
-        if (withTypeMapping) {
-            when(internal.typeMapping(TestItem.class)).thenReturn(typeMapping);
-            when(typeMapping.getResolver()).thenReturn(getResolver);
-        }
-    }
-
-    @NonNull
-    static GetObjectsStub newInstanceWithoutTypeMapping() {
-        return new GetObjectsStub(false);
-    }
-
-    @NonNull
-    static GetObjectsStub newInstanceWithTypeMapping() {
-        return new GetObjectsStub(true);
-    }
-
-    void verifyQueryBehavior(@NonNull List<TestItem> actualList) {
-        // should be called once
-        verify(storIOSQLite).get();
-
-        // should be called only once
-        verify(getResolver).performGet(storIOSQLite, query);
-
-        // should be called same number of times as number of items
-        verify(getResolver, times(items.size())).mapFromCursor(cursor);
-
-        // should be called only once because of Performance!
-        verify(cursor).getCount();
-
-        // should be called same number of times as count of items in cursor + 1 (last -> false)
-        verify(cursor, times(items.size() + 1)).moveToNext();
-
-        // cursor must be closed!
-        verify(cursor, times(1)).close();
-
-        // actual items should be equals to expected
-        assertEquals(items, actualList);
-
-        // list should be immutable!
-        assertThatListIsImmutable(actualList);
-
-        if (withTypeMapping) {
-            // should be called only once because of Performance!
-            verify(storIOSQLite).internal();
-
-            // should be called only once because of Performance!
-            verify(internal).typeMapping(TestItem.class);
-
-            // should be called only once because of Performance!
-            verify(typeMapping).getResolver();
-        }
-
-        verifyNoMoreInteractions(storIOSQLite, internal, cursor);
-    }
-
-    void verifyQueryBehavior(@NonNull Observable<List<TestItem>> observable) {
-        new ObservableBehaviorChecker<List<TestItem>>()
-                .observable(observable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<List<TestItem>>() {
-                    @Override
-                    public void call(List<TestItem> testItems) {
-                        // Get Operation should be subscribed to changes of tables from query
-                        verify(storIOSQLite).observeChangesInTables(eq(singleton(query.table())));
-
-                        verifyQueryBehavior(testItems);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-
-    void verifyRawQueryBehavior(@NonNull List<TestItem> actualList) {
-        assertNotNull(actualList);
-        verify(storIOSQLite, times(1)).get();
-        verify(getResolver, times(1)).performGet(storIOSQLite, rawQuery);
-        verify(getResolver, times(items.size())).mapFromCursor(cursor);
-        verify(cursor, times(1)).close();
-        assertEquals(items, actualList);
-        assertThatListIsImmutable(actualList);
-    }
-
-    void verifyRawQueryBehavior(@NonNull Observable<List<TestItem>> observable) {
-        new ObservableBehaviorChecker<List<TestItem>>()
-                .observable(observable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<List<TestItem>>() {
-                    @Override
-                    public void call(List<TestItem> testItems) {
-                        // Get Operation should be subscribed to changes of tables from query
-                        verify(storIOSQLite).observeChangesInTables(rawQuery.observesTables());
-
-                        verifyRawQueryBehavior(testItems);
-                    }
-                })
-                .checkBehaviorOfObservable();
-
-        assertNotNull(rawQuery.observesTables());
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetCursorTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetCursorTest.java
deleted file mode 100644
index ed148c9..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetCursorTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.get;
-
-import android.database.Cursor;
-
-import org.junit.Test;
-
-import rx.Observable;
-
-public class PreparedGetCursorTest {
-
-    @Test
-    public void shouldGetCursorWithQueryBlocking() {
-        final GetCursorStub getStub = GetCursorStub.newInstance();
-
-        final Cursor cursor = getStub.storIOSQLite
-                .get()
-                .cursor()
-                .withQuery(getStub.query)
-                .withGetResolver(getStub.getResolverForCursor)
-                .prepare()
-                .executeAsBlocking();
-
-        getStub.verifyQueryBehaviorForCursor(cursor);
-    }
-
-
-    @Test
-    public void shouldGetCursorWithQueryAsObservable() {
-        final GetCursorStub getStub = GetCursorStub.newInstance();
-
-        final Observable<Cursor> cursorObservable = getStub.storIOSQLite
-                .get()
-                .cursor()
-                .withQuery(getStub.query)
-                .withGetResolver(getStub.getResolverForCursor)
-                .prepare()
-                .createObservable()
-                .take(1);
-
-        getStub.verifyQueryBehaviorForCursor(cursorObservable);
-    }
-
-
-    @Test
-    public void shouldGetCursorWithRawQueryBlocking() {
-        final GetCursorStub getStub = GetCursorStub.newInstance();
-
-        final Cursor cursor = getStub.storIOSQLite
-                .get()
-                .cursor()
-                .withQuery(getStub.rawQuery)
-                .withGetResolver(getStub.getResolverForCursor)
-                .prepare()
-                .executeAsBlocking();
-
-        getStub.verifyRawQueryBehaviorForCursor(cursor);
-    }
-
-    @Test
-    public void shouldGetCursorWithRawQueryAsObservable() {
-        final GetCursorStub getStub = GetCursorStub.newInstance();
-
-        final Observable<Cursor> cursorObservable = getStub.storIOSQLite
-                .get()
-                .cursor()
-                .withQuery(getStub.rawQuery)
-                .withGetResolver(getStub.getResolverForCursor)
-                .prepare()
-                .createObservable()
-                .take(1);
-
-        getStub.verifyRawQueryBehaviorForCursor(cursorObservable);
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetListOfObjectsTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetListOfObjectsTest.java
deleted file mode 100644
index a6372d9..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/PreparedGetListOfObjectsTest.java
+++ /dev/null
@@ -1,276 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.get;
-
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.RawQuery;
-
-import org.junit.Test;
-import org.junit.experimental.runners.Enclosed;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-import java.util.Set;
-
-import rx.Observable;
-import rx.observers.TestSubscriber;
-
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anySet;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(Enclosed.class)
-public class PreparedGetListOfObjectsTest {
-
-    public static class WithoutTypeMapping {
-
-        @Test
-        public void shouldGetListOfObjectsByQueryWithoutTypeMappingBlocking() {
-            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithoutTypeMapping();
-
-            final List<TestItem> testItems = getStub.storIOSQLite
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(getStub.query)
-                    .withGetResolver(getStub.getResolver)
-                    .prepare()
-                    .executeAsBlocking();
-
-            getStub.verifyQueryBehavior(testItems);
-        }
-
-        @Test
-        public void shouldGetListOfObjectsByQueryWithoutTypeMappingAsObservable() {
-            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithoutTypeMapping();
-
-            final Observable<List<TestItem>> testItemsObservable = getStub.storIOSQLite
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(getStub.query)
-                    .withGetResolver(getStub.getResolver)
-                    .prepare()
-                    .createObservable()
-                    .take(1);
-
-            getStub.verifyQueryBehavior(testItemsObservable);
-        }
-
-        @Test
-        public void shouldGetListOfObjectsByRawQueryWithoutTypeMappingBlocking() {
-            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithoutTypeMapping();
-
-            final List<TestItem> testItems = getStub.storIOSQLite
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(getStub.rawQuery)
-                    .withGetResolver(getStub.getResolver)
-                    .prepare()
-                    .executeAsBlocking();
-
-            getStub.verifyRawQueryBehavior(testItems);
-        }
-
-        @Test
-        public void shouldGetListOfObjectsByRawQueryWithoutTypeMappingAsObservable() {
-            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithoutTypeMapping();
-
-            final Observable<List<TestItem>> testItemsObservable = getStub.storIOSQLite
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(getStub.rawQuery)
-                    .withGetResolver(getStub.getResolver)
-                    .prepare()
-                    .createObservable()
-                    .take(1);
-
-            getStub.verifyRawQueryBehavior(testItemsObservable);
-        }
-    }
-
-    public static class WithTypeMapping {
-
-        @Test
-        public void shouldGetListOfObjectsByQueryWithTypeMappingBlocking() {
-            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithTypeMapping();
-
-            final List<TestItem> testItems = getStub.storIOSQLite
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(getStub.query)
-                    .prepare()
-                    .executeAsBlocking();
-
-            getStub.verifyQueryBehavior(testItems);
-        }
-
-        @Test
-        public void shouldGetListOfObjectsByQueryWithTypeMappingAsObservable() {
-            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithTypeMapping();
-
-            final Observable<List<TestItem>> testItemsObservable = getStub.storIOSQLite
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(getStub.query)
-                    .prepare()
-                    .createObservable()
-                    .take(1);
-
-            getStub.verifyQueryBehavior(testItemsObservable);
-        }
-
-        @Test
-        public void shouldGetListOfObjectsByRawQueryWithTypeMappingBlocking() {
-            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithTypeMapping();
-
-            final List<TestItem> testItems = getStub.storIOSQLite
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(getStub.rawQuery)
-                    .prepare()
-                    .executeAsBlocking();
-
-            getStub.verifyRawQueryBehavior(testItems);
-        }
-
-        @Test
-        public void shouldGetListOfObjectsByRawQueryWithTypeMappingAsObservable() {
-            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithTypeMapping();
-
-            final Observable<List<TestItem>> testItemsObservable = getStub.storIOSQLite
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(getStub.rawQuery)
-                    .prepare()
-                    .createObservable()
-                    .take(1);
-
-            getStub.verifyRawQueryBehavior(testItemsObservable);
-        }
-    }
-
-    public static class NoTypeMappingError {
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAccessingDbWithQueryBlocking() {
-            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-            when(storIOSQLite.get()).thenReturn(new PreparedGet.Builder(storIOSQLite));
-            when(storIOSQLite.internal()).thenReturn(internal);
-
-            final PreparedGet<List<TestItem>> preparedGet = storIOSQLite
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(mock(Query.class))
-                    .prepare();
-
-            try {
-                preparedGet.executeAsBlocking();
-                fail();
-            } catch (IllegalStateException expected) {
-                // it's okay, no type mapping was found
-            }
-
-            verify(storIOSQLite).get();
-            verify(storIOSQLite).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).query(any(Query.class));
-            verifyNoMoreInteractions(storIOSQLite, internal);
-        }
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAccessingDbWithRawQueryBlocking() {
-            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-            when(storIOSQLite.get()).thenReturn(new PreparedGet.Builder(storIOSQLite));
-            when(storIOSQLite.internal()).thenReturn(internal);
-
-            final PreparedGet<List<TestItem>> preparedGet = storIOSQLite
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(mock(RawQuery.class))
-                    .prepare();
-
-            try {
-                preparedGet.executeAsBlocking();
-                fail();
-            } catch (IllegalStateException expected) {
-                // it's okay, no type mapping was found
-            }
-
-            verify(storIOSQLite).get();
-            verify(storIOSQLite).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).rawQuery(any(RawQuery.class));
-            verifyNoMoreInteractions(storIOSQLite, internal);
-        }
-
-        @SuppressWarnings("unchecked")
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAccessingDbWithQueryAsObservable() {
-            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-            when(storIOSQLite.get()).thenReturn(new PreparedGet.Builder(storIOSQLite));
-            when(storIOSQLite.internal()).thenReturn(internal);
-            when(storIOSQLite.observeChangesInTables(any(Set.class)))
-                    .thenReturn(Observable.empty());
-
-            final TestSubscriber<List<TestItem>> testSubscriber = new TestSubscriber<List<TestItem>>();
-
-            storIOSQLite
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(mock(Query.class))
-                    .prepare()
-                    .createObservable()
-                    .subscribe(testSubscriber);
-
-            testSubscriber.awaitTerminalEvent();
-            testSubscriber.assertNoValues();
-            testSubscriber.assertError(IllegalStateException.class);
-
-            verify(storIOSQLite).get();
-            verify(storIOSQLite).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).query(any(Query.class));
-            verify(storIOSQLite).observeChangesInTables(anySet());
-            verifyNoMoreInteractions(storIOSQLite, internal);
-        }
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAccessingDbWithRawQueryAsObservable() {
-            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-            when(storIOSQLite.get()).thenReturn(new PreparedGet.Builder(storIOSQLite));
-            when(storIOSQLite.internal()).thenReturn(internal);
-
-            final TestSubscriber<List<TestItem>> testSubscriber = new TestSubscriber<List<TestItem>>();
-
-            storIOSQLite
-                    .get()
-                    .listOfObjects(TestItem.class)
-                    .withQuery(mock(RawQuery.class))
-                    .prepare()
-                    .createObservable()
-                    .subscribe(testSubscriber);
-
-            testSubscriber.awaitTerminalEvent();
-            testSubscriber.assertNoValues();
-            testSubscriber.assertError(IllegalStateException.class);
-
-            verify(storIOSQLite).get();
-            verify(storIOSQLite).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).rawQuery(any(RawQuery.class));
-            verifyNoMoreInteractions(storIOSQLite, internal);
-        }
-    }
-
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/TestItem.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/TestItem.java
deleted file mode 100644
index 22c7749..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/get/TestItem.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.get;
-
-import java.util.concurrent.atomic.AtomicLong;
-
-class TestItem {
-
-    private static final AtomicLong COUNTER = new AtomicLong(0);
-
-    private Long id = COUNTER.incrementAndGet();
-
-    public Long getId() {
-        return id;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        TestItem testItem = (TestItem) o;
-
-        return !(id != null ? !id.equals(testItem.id) : testItem.id != null);
-    }
-
-    @Override
-    public int hashCode() {
-        return id != null ? id.hashCode() : 0;
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/DefaultPutResolverTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/DefaultPutResolverTest.java
deleted file mode 100644
index feda517..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/DefaultPutResolverTest.java
+++ /dev/null
@@ -1,267 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.InsertQuery;
-import com.pushtorefresh.storio.sqlite.query.Query;
-import com.pushtorefresh.storio.sqlite.query.UpdateQuery;
-
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import rx.functions.Func1;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class DefaultPutResolverTest {
-
-    /**
-     * Verifies behavior of {@link DefaultPutResolver} for "insert"
-     */
-    @Test
-    public void insert() {
-        final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-        final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-        final TestItem testItem = new TestItem(null); // item without id, should be inserted
-
-        when(storIOSQLite.internal())
-                .thenReturn(internal);
-
-        final Long expectedInsertedId = 24L;
-
-        final Query expectedQuery = Query.builder()
-                .table(TestItem.TABLE)
-                .where(TestItem.COLUMN_ID + " = ?")
-                .whereArgs(testItem.getId())
-                .build();
-
-        final Cursor cursor = mock(Cursor.class);
-
-        when(internal.query(eq(expectedQuery)))
-                .thenReturn(cursor);
-
-        when(cursor.getCount())
-                .thenReturn(0); // No results -> insert should be performed
-
-        when(internal.insert(any(InsertQuery.class), any(ContentValues.class)))
-                .thenReturn(expectedInsertedId);
-
-        final InsertQuery expectedInsertQuery = InsertQuery.builder()
-                .table(TestItem.TABLE)
-                .nullColumnHack(null)
-                .build();
-
-        final PutResolver<TestItem> putResolver = new DefaultPutResolver<TestItem>() {
-            @NonNull
-            @Override
-            protected InsertQuery mapToInsertQuery(@NonNull TestItem object) {
-                return expectedInsertQuery;
-            }
-
-            @NonNull
-            @Override
-            protected UpdateQuery mapToUpdateQuery(@NonNull TestItem object) {
-                return UpdateQuery.builder()
-                        .table(TestItem.TABLE)
-                        .where(TestItem.COLUMN_ID + " = ?")
-                        .whereArgs(object.getId())
-                        .build();
-            }
-
-            @NonNull
-            @Override
-            protected ContentValues mapToContentValues(@NonNull TestItem object) {
-                return TestItem.MAP_TO_CONTENT_VALUES.call(object);
-            }
-        };
-
-        final ContentValues expectedContentValues = TestItem.MAP_TO_CONTENT_VALUES.call(testItem);
-
-        // Performing Put that should "insert"
-        final PutResult putResult = putResolver.performPut(storIOSQLite, testItem);
-
-        verify(internal, times(1)).beginTransaction();
-        verify(internal, times(1)).setTransactionSuccessful();
-        verify(internal, times(1)).endTransaction();
-
-        // checks that it asks db for results
-        verify(internal, times(1)).query(eq(expectedQuery));
-
-        // checks that cursor was closed
-        verify(cursor, times(1)).close();
-
-        // only one query should occur
-        verify(internal, times(1)).query(any(Query.class));
-
-        // checks that required insert was performed
-        verify(internal, times(1)).insert(eq(expectedInsertQuery), eq(expectedContentValues));
-
-        // only one insert should occur
-        verify(internal, times(1)).insert(any(InsertQuery.class), any(ContentValues.class));
-
-        // no updates should occur
-        verify(internal, times(0)).update(any(UpdateQuery.class), any(ContentValues.class));
-
-        // put result checks
-        assertTrue(putResult.wasInserted());
-        assertFalse(putResult.wasUpdated());
-
-        assertEquals(expectedInsertedId, putResult.insertedId());
-        assertNull(putResult.numberOfRowsUpdated());
-    }
-
-    /**
-     * Verifies behavior of {@link DefaultPutResolver} for "update"
-     */
-    @Test
-    public void update() {
-        final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-        final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-        final TestItem testItem = new TestItem(null); // item with some id, should be updated
-
-        when(storIOSQLite.internal())
-                .thenReturn(internal);
-
-        final Query expectedQuery = Query.builder()
-                .table(TestItem.TABLE)
-                .where(TestItem.COLUMN_ID + " = ?")
-                .whereArgs(testItem.getId())
-                .build();
-
-        final Cursor cursor = mock(Cursor.class);
-
-        when(internal.query(eq(expectedQuery)))
-                .thenReturn(cursor);
-
-        when(cursor.getCount())
-                .thenReturn(1); // Some rows already in db -> update should be performed
-
-        final Integer expectedNumberOfRowsUpdated = 1;
-
-        when(internal.update(any(UpdateQuery.class), any(ContentValues.class)))
-                .thenReturn(expectedNumberOfRowsUpdated);
-
-        final UpdateQuery expectedUpdateQuery = UpdateQuery.builder()
-                .table(TestItem.TABLE)
-                .where(TestItem.COLUMN_ID + " = ?")
-                .whereArgs(testItem.getId())
-                .build();
-
-        final PutResolver<TestItem> putResolver = new DefaultPutResolver<TestItem>() {
-            @NonNull
-            @Override
-            protected InsertQuery mapToInsertQuery(@NonNull TestItem object) {
-                fail("Should not be called");
-                return null;
-            }
-
-            @NonNull
-            @Override
-            protected UpdateQuery mapToUpdateQuery(@NonNull TestItem object) {
-                return UpdateQuery.builder()
-                        .table(TestItem.TABLE)
-                        .where(TestItem.COLUMN_ID + " = ?")
-                        .whereArgs(object.getId())
-                        .build();
-            }
-
-            @NonNull
-            @Override
-            protected ContentValues mapToContentValues(@NonNull TestItem object) {
-                return TestItem.MAP_TO_CONTENT_VALUES.call(object);
-            }
-        };
-
-        final ContentValues expectedContentValues = TestItem.MAP_TO_CONTENT_VALUES.call(testItem);
-
-        // Performing Put that should "update"
-        final PutResult putResult = putResolver.performPut(storIOSQLite, testItem);
-
-        verify(internal, times(1)).beginTransaction();
-        verify(internal, times(1)).setTransactionSuccessful();
-        verify(internal, times(1)).endTransaction();
-
-        // checks that it asks db for results
-        verify(internal, times(1)).query(eq(expectedQuery));
-
-        // checks that cursor was closed
-        verify(cursor, times(1)).close();
-
-        // only one query should occur
-        verify(internal, times(1)).query(any(Query.class));
-
-        // checks that required update was performed
-        verify(internal, times(1)).update(eq(expectedUpdateQuery), eq(expectedContentValues));
-
-        // only one update should occur
-        verify(internal, times(1)).update(any(UpdateQuery.class), any(ContentValues.class));
-
-        // no inserts should occur
-        verify(internal, times(0)).insert(any(InsertQuery.class), any(ContentValues.class));
-
-        // put result checks
-        assertFalse(putResult.wasInserted());
-        assertTrue(putResult.wasUpdated());
-
-        assertEquals(expectedNumberOfRowsUpdated, putResult.numberOfRowsUpdated());
-        assertNull(putResult.insertedId());
-    }
-
-    private static class TestItem {
-
-        final static String TABLE = "someTable";
-        final static String COLUMN_ID = "customIdColumnName";
-        @Nullable
-        private final Long id;
-        static final Func1<TestItem, ContentValues> MAP_TO_CONTENT_VALUES = new Func1<TestItem, ContentValues>() {
-
-            // ContentValues should be mocked for usage in tests (damn you Android...)
-            // but we can not mock equals() method
-            // so, we will return SAME ContentValues for object and assertEquals() will pass
-            @NonNull
-            private final Map<TestItem, ContentValues> map = new HashMap<TestItem, ContentValues>();
-
-            @NonNull
-            @Override
-            public ContentValues call(@NonNull TestItem testItem) {
-                if (map.containsKey(testItem)) {
-                    return map.get(testItem);
-                } else {
-                    final ContentValues contentValues = mock(ContentValues.class);
-
-                    when(contentValues.get(COLUMN_ID))
-                            .thenReturn(testItem.id);
-
-                    map.put(testItem, contentValues); // storing pair of mapping
-
-                    return contentValues;
-                }
-            }
-        };
-
-        TestItem(@Nullable Long id) {
-            this.id = id;
-        }
-
-        @Nullable
-        Long getId() {
-            return id;
-        }
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutCollectionOfObjectsTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutCollectionOfObjectsTest.java
deleted file mode 100644
index f8e03a4..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutCollectionOfObjectsTest.java
+++ /dev/null
@@ -1,292 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.content.ContentValues;
-
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.sqlite.query.InsertQuery;
-import com.pushtorefresh.storio.sqlite.query.UpdateQuery;
-
-import org.junit.Test;
-import org.junit.experimental.runners.Enclosed;
-import org.junit.runner.RunWith;
-
-import java.util.List;
-
-import rx.Observable;
-import rx.observers.TestSubscriber;
-
-import static java.util.Arrays.asList;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-@RunWith(Enclosed.class)
-public class PreparedPutCollectionOfObjectsTest {
-
-    public static class WithoutTypeMapping {
-
-        @Test
-        public void shouldPutObjectsWithoutTypeMappingWithoutTransactionBlocking() {
-            final PutObjectsStub putStub
-                    = PutObjectsStub.newPutStubForMultipleObjectsWithoutTypeMappingWithoutTransaction();
-
-            final PutResults<TestItem> putResults = putStub.storIOSQLite
-                    .put()
-                    .objects(putStub.items)
-                    .useTransaction(false)
-                    .withPutResolver(putStub.putResolver)
-                    .prepare()
-                    .executeAsBlocking();
-
-            putStub.verifyBehaviorForMultipleObjects(putResults);
-        }
-
-        @Test
-        public void shouldPutObjectsWithoutTypeMappingWithTransactionBlocking() {
-            final PutObjectsStub putStub
-                    = PutObjectsStub.newPutStubForMultipleObjectsWithoutTypeMappingWithTransaction();
-
-            final PutResults<TestItem> putResults = putStub.storIOSQLite
-                    .put()
-                    .objects(putStub.items)
-                    .useTransaction(true)
-                    .withPutResolver(putStub.putResolver)
-                    .prepare()
-                    .executeAsBlocking();
-
-            putStub.verifyBehaviorForMultipleObjects(putResults);
-        }
-
-        @Test
-        public void shouldPutObjectsWithoutTypeMappingWithoutTransactionAsObservable() {
-            final PutObjectsStub putStub
-                    = PutObjectsStub.newPutStubForMultipleObjectsWithoutTypeMappingWithoutTransaction();
-
-            final Observable<PutResults<TestItem>> observable = putStub.storIOSQLite
-                    .put()
-                    .objects(putStub.items)
-                    .useTransaction(false)
-                    .withPutResolver(putStub.putResolver)
-                    .prepare()
-                    .createObservable();
-
-            putStub.verifyBehaviorForMultipleObjects(observable);
-        }
-
-        @Test
-        public void shouldPutObjectsWithoutTypeMappingWithTransactionAsObservable() {
-            final PutObjectsStub putStub
-                    = PutObjectsStub.newPutStubForMultipleObjectsWithoutTypeMappingWithTransaction();
-
-            final Observable<PutResults<TestItem>> observable = putStub.storIOSQLite
-                    .put()
-                    .objects(putStub.items)
-                    .useTransaction(true)
-                    .withPutResolver(putStub.putResolver)
-                    .prepare()
-                    .createObservable();
-
-            putStub.verifyBehaviorForMultipleObjects(observable);
-        }
-    }
-
-    public static class WithTypeMapping {
-
-        @Test
-        public void shouldPutObjectsWithTypeMappingWithoutTransactionBlocking() {
-            final PutObjectsStub putStub
-                    = PutObjectsStub.newPutStubForMultipleObjectsWithTypeMappingWithoutTransaction();
-
-            final PutResults<TestItem> putResults = putStub.storIOSQLite
-                    .put()
-                    .objects(putStub.items)
-                    .useTransaction(false)
-                    .prepare()
-                    .executeAsBlocking();
-
-            putStub.verifyBehaviorForMultipleObjects(putResults);
-        }
-
-        @Test
-        public void shouldPutObjectsWithTypeMappingWithTransactionBlocking() {
-            final PutObjectsStub putStub
-                    = PutObjectsStub.newPutStubForMultipleObjectsWithTypeMappingWithTransaction();
-
-            final PutResults<TestItem> putResults = putStub.storIOSQLite
-                    .put()
-                    .objects(putStub.items)
-                    .useTransaction(true)
-                    .prepare()
-                    .executeAsBlocking();
-
-            putStub.verifyBehaviorForMultipleObjects(putResults);
-        }
-
-        @Test
-        public void shouldPutObjectsWithTypeMappingWithoutTransactionAsObservable() {
-            final PutObjectsStub putStub
-                    = PutObjectsStub.newPutStubForMultipleObjectsWithTypeMappingWithoutTransaction();
-
-            final Observable<PutResults<TestItem>> observable = putStub.storIOSQLite
-                    .put()
-                    .objects(putStub.items)
-                    .useTransaction(false)
-                    .prepare()
-                    .createObservable();
-
-            putStub.verifyBehaviorForMultipleObjects(observable);
-        }
-
-        @Test
-        public void shouldPutObjectsWithTypeMappingWithTransactionAsObservable() {
-            final PutObjectsStub putStub
-                    = PutObjectsStub.newPutStubForMultipleObjectsWithTypeMappingWithTransaction();
-
-            final Observable<PutResults<TestItem>> observable = putStub.storIOSQLite
-                    .put()
-                    .objects(putStub.items)
-                    .useTransaction(true)
-                    .prepare()
-                    .createObservable();
-
-            putStub.verifyBehaviorForMultipleObjects(observable);
-        }
-    }
-
-    public static class NoTypeMappingError {
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutTransactionWithoutAffectingDbBlocking() {
-            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-            when(storIOSQLite.internal()).thenReturn(internal);
-
-            when(storIOSQLite.put()).thenReturn(new PreparedPut.Builder(storIOSQLite));
-
-            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
-
-            final PreparedPut<PutResults<TestItem>> preparedPut = storIOSQLite
-                    .put()
-                    .objects(items)
-                    .useTransaction(false)
-                    .prepare();
-
-            try {
-                preparedPut.executeAsBlocking();
-                fail();
-            } catch (IllegalStateException expected) {
-                // it's okay, no type mapping was found
-            }
-
-            verify(storIOSQLite).put();
-            verify(storIOSQLite).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
-            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
-            verifyNoMoreInteractions(storIOSQLite, internal);
-        }
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutTransactionWithoutAffectingDbAsObservable() {
-            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-            when(storIOSQLite.internal()).thenReturn(internal);
-
-            when(storIOSQLite.put()).thenReturn(new PreparedPut.Builder(storIOSQLite));
-
-            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
-
-            final TestSubscriber<PutResults<TestItem>> testSubscriber = new TestSubscriber<PutResults<TestItem>>();
-
-            storIOSQLite
-                    .put()
-                    .objects(items)
-                    .useTransaction(false)
-                    .prepare()
-                    .createObservable()
-                    .subscribe(testSubscriber);
-
-            testSubscriber.awaitTerminalEvent();
-            testSubscriber.assertNoValues();
-            testSubscriber.assertError(IllegalStateException.class);
-
-            verify(storIOSQLite).put();
-            verify(storIOSQLite).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
-            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
-            verifyNoMoreInteractions(storIOSQLite, internal);
-        }
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithTransactionWithoutAffectingDbBlocking() {
-            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-            when(storIOSQLite.internal()).thenReturn(internal);
-
-            when(storIOSQLite.put()).thenReturn(new PreparedPut.Builder(storIOSQLite));
-
-            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
-
-            final PreparedPut<PutResults<TestItem>> preparedPut = storIOSQLite
-                    .put()
-                    .objects(items)
-                    .useTransaction(true)
-                    .prepare();
-
-            try {
-                preparedPut.executeAsBlocking();
-                fail();
-            } catch (IllegalStateException expected) {
-                // it's okay, no type mapping was found
-            }
-
-            verify(storIOSQLite).put();
-            verify(storIOSQLite).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
-            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
-            verifyNoMoreInteractions(storIOSQLite, internal);
-        }
-
-        @Test
-        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithTransactionWithoutAffectingDbAsObservable() {
-            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
-            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
-
-            when(storIOSQLite.internal()).thenReturn(internal);
-
-            when(storIOSQLite.put()).thenReturn(new PreparedPut.Builder(storIOSQLite));
-
-            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
-
-            final TestSubscriber<PutResults<TestItem>> testSubscriber = new TestSubscriber<PutResults<TestItem>>();
-
-            storIOSQLite
-                    .put()
-                    .objects(items)
-                    .useTransaction(true)
-                    .prepare()
-                    .createObservable()
-                    .subscribe(testSubscriber);
-
-            testSubscriber.awaitTerminalEvent();
-            testSubscriber.assertNoValues();
-            testSubscriber.assertError(IllegalStateException.class);
-
-            verify(storIOSQLite).put();
-            verify(storIOSQLite).internal();
-            verify(internal).typeMapping(TestItem.class);
-            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
-            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
-            verifyNoMoreInteractions(storIOSQLite, internal);
-        }
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValuesIterableTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValuesIterableTest.java
deleted file mode 100644
index 2239c5f..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValuesIterableTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.content.ContentValues;
-
-import org.junit.Test;
-
-import rx.Observable;
-
-public class PreparedPutContentValuesIterableTest {
-
-    @Test
-    public void putMultipleBlockingWithTransaction() {
-        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForMultipleContentValues(true);
-
-        final PutResults<ContentValues> putResults = putStub.storIOSQLite
-                .put()
-                .contentValues(putStub.contentValues)
-                .withPutResolver(putStub.putResolver)
-                .useTransaction(true)
-                .prepare()
-                .executeAsBlocking();
-
-        putStub.verifyBehaviorForMultipleContentValues(putResults);
-    }
-
-    @Test
-    public void putMultipleObservableWithTransaction() {
-        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForMultipleContentValues(true);
-
-        final Observable<PutResults<ContentValues>> putResultsObservable = putStub.storIOSQLite
-                .put()
-                .contentValues(putStub.contentValues)
-                .withPutResolver(putStub.putResolver)
-                .useTransaction(true)
-                .prepare()
-                .createObservable();
-
-        putStub.verifyBehaviorForMultipleContentValues(putResultsObservable);
-    }
-
-    @Test
-    public void putMultipleBlockingWithoutTransaction() {
-        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForMultipleContentValues(false);
-
-        final PutResults<ContentValues> putResults = putStub.storIOSQLite
-                .put()
-                .contentValues(putStub.contentValues)
-                .withPutResolver(putStub.putResolver)
-                .useTransaction(false)
-                .prepare()
-                .executeAsBlocking();
-
-        putStub.verifyBehaviorForMultipleContentValues(putResults);
-    }
-
-    @Test
-    public void putMultipleObservableWithoutTransaction() {
-        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForMultipleContentValues(false);
-
-        final Observable<PutResults<ContentValues>> putResultsObservable = putStub.storIOSQLite
-                .put()
-                .contentValues(putStub.contentValues)
-                .withPutResolver(putStub.putResolver)
-                .useTransaction(false)
-                .prepare()
-                .createObservable();
-
-        putStub.verifyBehaviorForMultipleContentValues(putResultsObservable);
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValuesTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValuesTest.java
deleted file mode 100644
index d430027..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutContentValuesTest.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import org.junit.Test;
-
-import rx.Observable;
-
-public class PreparedPutContentValuesTest {
-
-    @Test
-    public void putContentValuesBlocking() {
-        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForOneContentValues();
-
-        final PutResult putResult = putStub.storIOSQLite
-                .put()
-                .contentValues(putStub.contentValues.get(0))
-                .withPutResolver(putStub.putResolver)
-                .prepare()
-                .executeAsBlocking();
-
-        putStub.verifyBehaviorForOneContentValues(putResult);
-    }
-
-    @Test
-    public void putContentValuesObservable() {
-        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForOneContentValues();
-
-        final Observable<PutResult> putResultObservable = putStub.storIOSQLite
-                .put()
-                .contentValues(putStub.contentValues.get(0))
-                .withPutResolver(putStub.putResolver)
-                .prepare()
-                .createObservable();
-
-        putStub.verifyBehaviorForOneContentValues(putResultObservable);
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutObjectTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutObjectTest.java
deleted file mode 100644
index d4b46c9..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PreparedPutObjectTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import org.junit.Test;
-import org.junit.experimental.runners.Enclosed;
-import org.junit.runner.RunWith;
-
-import rx.Observable;
-
-@RunWith(Enclosed.class)
-public class PreparedPutObjectTest {
-
-    public static class WithoutTypeMapping {
-
-        @Test
-        public void shouldPutObjectWithoutTypeMappingBlocking() {
-            final PutObjectsStub putStub = PutObjectsStub.newPutStubForOneObjectWithoutTypeMapping();
-
-            final PutResult putResult = putStub.storIOSQLite
-                    .put()
-                    .object(putStub.items.get(0))
-                    .withPutResolver(putStub.putResolver)
-                    .prepare()
-                    .executeAsBlocking();
-
-            putStub.verifyBehaviorForOneObject(putResult);
-        }
-
-        @Test
-        public void shouldPutObjectWithoutTypeMappingAsObservable() {
-            final PutObjectsStub putStub = PutObjectsStub.newPutStubForOneObjectWithoutTypeMapping();
-
-            final Observable<PutResult> putResultObservable = putStub.storIOSQLite
-                    .put()
-                    .object(putStub.items.get(0))
-                    .withPutResolver(putStub.putResolver)
-                    .prepare()
-                    .createObservable();
-
-            putStub.verifyBehaviorForOneObject(putResultObservable);
-        }
-    }
-
-
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PutContentValuesStub.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PutContentValuesStub.java
deleted file mode 100644
index 9f7efb2..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PutContentValuesStub.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.content.ContentValues;
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.sqlite.Changes;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import rx.Observable;
-import rx.functions.Action1;
-
-import static java.util.Collections.singletonMap;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-// stub class to avoid violation of DRY in tests
-class PutContentValuesStub {
-
-    @NonNull
-    final StorIOSQLite storIOSQLite;
-
-    @NonNull
-    private final StorIOSQLite.Internal internal;
-
-    @NonNull
-    final List<ContentValues> contentValues;
-
-    @NonNull
-    final PutResolver<ContentValues> putResolver;
-
-    private final boolean useTransaction;
-
-    @SuppressWarnings("unchecked")
-    private PutContentValuesStub(boolean useTransaction, int numberOfItems) {
-        this.useTransaction = useTransaction;
-
-        storIOSQLite = mock(StorIOSQLite.class);
-        internal = mock(StorIOSQLite.Internal.class);
-
-        when(storIOSQLite.internal())
-                .thenReturn(internal);
-
-        when(storIOSQLite.put())
-                .thenReturn(new PreparedPut.Builder(storIOSQLite));
-
-        contentValues = new ArrayList<ContentValues>(numberOfItems);
-
-        for (int i = 0; i < numberOfItems; i++) {
-            contentValues.add(mock(ContentValues.class));
-        }
-
-        putResolver = (PutResolver<ContentValues>) mock(PutResolver.class);
-
-        when(putResolver.performPut(eq(storIOSQLite), any(ContentValues.class)))
-                .thenReturn(PutResult.newInsertResult(1, TestItem.TABLE));
-    }
-
-    @NonNull
-    static PutContentValuesStub newPutStubForOneContentValues() {
-        return new PutContentValuesStub(false, 1);
-    }
-
-    @NonNull
-    static PutContentValuesStub newPutStubForMultipleContentValues(boolean useTransaction) {
-        return new PutContentValuesStub(useTransaction, 3);
-    }
-
-    void verifyBehaviorForMultipleContentValues(@NonNull PutResults<ContentValues> putResults) {
-        // only one call to storIOSQLite.put() should occur
-        verify(storIOSQLite, times(1)).put();
-
-        // number of calls to putResolver's performPut() should be equal to number of objects
-        verify(putResolver, times(contentValues.size())).performPut(eq(storIOSQLite), any(ContentValues.class));
-
-        // each item should be "put"
-        for (final ContentValues cv : contentValues) {
-            verify(putResolver, times(1)).performPut(storIOSQLite, cv);
-        }
-
-        verifyTransactionBehavior();
-    }
-
-    void verifyBehaviorForMultipleContentValues(@NonNull Observable<PutResults<ContentValues>> putResultsObservable) {
-        new ObservableBehaviorChecker<PutResults<ContentValues>>()
-                .observable(putResultsObservable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<PutResults<ContentValues>>() {
-                    @Override
-                    public void call(PutResults<ContentValues> putResults) {
-                        verifyBehaviorForMultipleContentValues(putResults);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-
-    void verifyBehaviorForOneContentValues(@NonNull PutResult putResult) {
-        verifyBehaviorForMultipleContentValues(PutResults.newInstance(singletonMap(contentValues.get(0), putResult)));
-    }
-
-    void verifyBehaviorForOneContentValues(@NonNull Observable<PutResult> putResultObservable) {
-        new ObservableBehaviorChecker<PutResult>()
-                .observable(putResultObservable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<PutResult>() {
-                    @Override
-                    public void call(PutResult putResult) {
-                        verifyBehaviorForOneContentValues(putResult);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-
-    private void verifyTransactionBehavior() {
-        if (useTransaction) {
-            verify(internal, times(1)).beginTransaction();
-            verify(internal, times(1)).setTransactionSuccessful();
-            verify(internal, times(1)).endTransaction();
-
-            // if put() operation used transaction, only one notification should be thrown
-            verify(internal, times(1))
-                    .notifyAboutChanges(eq(Changes.newInstance(TestItem.TABLE)));
-        } else {
-            verify(internal, times(0)).beginTransaction();
-            verify(internal, times(0)).setTransactionSuccessful();
-            verify(internal, times(0)).endTransaction();
-
-            // if put() operation didn't use transaction,
-            // number of notifications should be equal to number of objects
-            verify(internal, times(contentValues.size()))
-                    .notifyAboutChanges(eq(Changes.newInstance(TestItem.TABLE)));
-        }
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PutObjectsStub.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PutObjectsStub.java
deleted file mode 100644
index 434aa30..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/PutObjectsStub.java
+++ /dev/null
@@ -1,216 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.support.annotation.NonNull;
-
-import com.pushtorefresh.storio.sqlite.Changes;
-import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
-import com.pushtorefresh.storio.sqlite.StorIOSQLite;
-import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
-
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import rx.Observable;
-import rx.functions.Action1;
-
-import static java.util.Collections.singleton;
-import static java.util.Collections.singletonMap;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-// stub class to avoid violation of DRY in tests
-class PutObjectsStub {
-
-    @NonNull
-    final StorIOSQLite storIOSQLite;
-
-    @NonNull
-    private final StorIOSQLite.Internal internal;
-
-    @NonNull
-    final List<TestItem> items;
-
-    @NonNull
-    final PutResolver<TestItem> putResolver;
-
-    @NonNull
-    private final SQLiteTypeMapping<TestItem> typeMapping;
-
-    @NonNull
-    private final Map<TestItem, PutResult> itemsToPutResultsMap;
-
-    private final boolean withTypeMapping, useTransaction;
-
-    @SuppressWarnings("unchecked")
-    private PutObjectsStub(boolean withTypeMapping, boolean useTransaction, int numberOfItems) {
-        this.withTypeMapping = withTypeMapping;
-        this.useTransaction = useTransaction;
-
-        storIOSQLite = mock(StorIOSQLite.class);
-        internal = mock(StorIOSQLite.Internal.class);
-
-        when(storIOSQLite.internal())
-                .thenReturn(internal);
-
-        when(storIOSQLite.put())
-                .thenReturn(new PreparedPut.Builder(storIOSQLite));
-
-        items = new ArrayList<TestItem>(numberOfItems);
-        itemsToPutResultsMap = new HashMap<TestItem, PutResult>(numberOfItems);
-
-        for (int i = 0; i < numberOfItems; i++) {
-            final TestItem testItem = TestItem.newInstance();
-            items.add(testItem);
-
-            final PutResult putResult = mock(PutResult.class);
-
-            when(putResult.affectedTables()).thenReturn(singleton(TestItem.TABLE));
-
-            itemsToPutResultsMap.put(testItem, putResult);
-        }
-
-        putResolver = (PutResolver<TestItem>) mock(PutResolver.class);
-
-        when(putResolver.performPut(eq(storIOSQLite), any(TestItem.class)))
-                .thenAnswer(new Answer<PutResult>() {
-                    @SuppressWarnings("SuspiciousMethodCalls")
-                    @Override
-                    public PutResult answer(InvocationOnMock invocation) throws Throwable {
-                        return itemsToPutResultsMap.get(invocation.getArguments()[1]);
-                    }
-                });
-
-        typeMapping = mock(SQLiteTypeMapping.class);
-
-        if (withTypeMapping) {
-            when(internal.typeMapping(TestItem.class)).thenReturn(typeMapping);
-            when(typeMapping.putResolver()).thenReturn(putResolver);
-        }
-    }
-
-    @NonNull
-    static PutObjectsStub newPutStubForOneObjectWithoutTypeMapping() {
-        return new PutObjectsStub(false, false, 1);
-    }
-
-    @NonNull
-    static PutObjectsStub newPutStubForOneObjectWithTypeMapping() {
-        return new PutObjectsStub(true, false, 1);
-    }
-
-    @NonNull
-    static PutObjectsStub newPutStubForMultipleObjectsWithoutTypeMappingWithTransaction() {
-        return new PutObjectsStub(false, true, 3);
-    }
-
-    @NonNull
-    static PutObjectsStub newPutStubForMultipleObjectsWithTypeMappingWithTransaction() {
-        return new PutObjectsStub(true, true, 3);
-    }
-
-    @NonNull
-    static PutObjectsStub newPutStubForMultipleObjectsWithoutTypeMappingWithoutTransaction() {
-        return new PutObjectsStub(false, false, 3);
-    }
-
-    @NonNull
-    static PutObjectsStub newPutStubForMultipleObjectsWithTypeMappingWithoutTransaction() {
-        return new PutObjectsStub(true, false, 3);
-    }
-
-    void verifyBehaviorForMultipleObjects(@NonNull PutResults<TestItem> putResults) {
-        // should be called once because of Performance!
-        verify(storIOSQLite).internal();
-
-        // only one call to storIOSQLite.put() should occur
-        verify(storIOSQLite, times(1)).put();
-
-        // number of calls to putResolver's performPut() should be equal to number of objects
-        verify(putResolver, times(items.size())).performPut(eq(storIOSQLite), any(TestItem.class));
-
-        for (final TestItem testItem : items) {
-            // put resolver should be invoked for each item
-            verify(putResolver, times(1)).performPut(storIOSQLite, testItem);
-
-            final PutResult expectedPutResult = itemsToPutResultsMap.get(testItem);
-
-            assertEquals(expectedPutResult, putResults.results().get(testItem));
-        }
-
-        assertEquals(itemsToPutResultsMap.size(), putResults.results().size());
-
-        verifyTransactionBehavior();
-
-        if (withTypeMapping) {
-            // should be called for each item
-            verify(internal, times(items.size())).typeMapping(TestItem.class);
-
-            // should be called for each item
-            verify(typeMapping, times(items.size())).putResolver();
-        }
-
-        verifyNoMoreInteractions(storIOSQLite, internal, typeMapping, putResolver);
-    }
-
-    void verifyBehaviorForMultipleObjects(@NonNull Observable<PutResults<TestItem>> putResultsObservable) {
-        new ObservableBehaviorChecker<PutResults<TestItem>>()
-                .observable(putResultsObservable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<PutResults<TestItem>>() {
-                    @Override
-                    public void call(PutResults<TestItem> testItemPutResults) {
-                        verifyBehaviorForMultipleObjects(testItemPutResults);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-
-    void verifyBehaviorForOneObject(@NonNull PutResult putResult) {
-        verifyBehaviorForMultipleObjects(PutResults.newInstance(singletonMap(items.get(0), putResult)));
-    }
-
-    void verifyBehaviorForOneObject(@NonNull Observable<PutResult> putResultObservable) {
-        new ObservableBehaviorChecker<PutResult>()
-                .observable(putResultObservable)
-                .expectedNumberOfEmissions(1)
-                .testAction(new Action1<PutResult>() {
-                    @Override
-                    public void call(PutResult putResult) {
-                        verifyBehaviorForOneObject(putResult);
-                    }
-                })
-                .checkBehaviorOfObservable();
-    }
-
-    private void verifyTransactionBehavior() {
-        if (useTransaction) {
-            verify(internal, times(1)).beginTransaction();
-            verify(internal, times(1)).setTransactionSuccessful();
-            verify(internal, times(1)).endTransaction();
-
-            // if put() operation used transaction, only one notification should be thrown
-            verify(internal, times(1))
-                    .notifyAboutChanges(eq(Changes.newInstance(TestItem.TABLE)));
-        } else {
-            verify(internal, times(0)).beginTransaction();
-            verify(internal, times(0)).setTransactionSuccessful();
-            verify(internal, times(0)).endTransaction();
-
-            // if put() operation didn't use transaction,
-            // number of notifications should be equal to number of objects
-            verify(internal, times(items.size()))
-                    .notifyAboutChanges(eq(Changes.newInstance(TestItem.TABLE)));
-        }
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/TestItem.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/TestItem.java
deleted file mode 100644
index 468c6f5..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operation/put/TestItem.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.pushtorefresh.storio.sqlite.operation.put;
-
-import android.support.annotation.NonNull;
-
-class TestItem {
-    static final String TABLE = "test_items";
-
-    private TestItem() {
-
-    }
-
-    @NonNull
-    static TestItem newInstance() {
-        return new TestItem();
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DefaultDeleteResolverTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DefaultDeleteResolverTest.java
new file mode 100644
index 0000000..1347408
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DefaultDeleteResolverTest.java
@@ -0,0 +1,59 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+
+import org.junit.Test;
+
+import java.util.Collections;
+
+import static junit.framework.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class DefaultDeleteResolverTest {
+
+    @Test
+    public void performDelete() {
+        final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+        final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+        final String testTable = "test_table";
+        final DeleteQuery deleteQuery = DeleteQuery.builder()
+                .table(testTable)
+                .build();
+
+        when(storIOSQLite.internal())
+                .thenReturn(internal);
+
+        when(internal.delete(deleteQuery))
+                .thenReturn(1);
+
+        final TestItem testItem = new TestItem();
+
+        final DefaultDeleteResolver<TestItem> defaultDeleteResolver = new DefaultDeleteResolver<TestItem>() {
+            @NonNull
+            @Override
+            public DeleteQuery mapToDeleteQuery(@NonNull TestItem testItem) {
+                return deleteQuery;
+            }
+        };
+
+        final DeleteResult deleteResult = defaultDeleteResolver.performDelete(storIOSQLite, testItem);
+
+        verify(internal, times(1)).delete(any(DeleteQuery.class));
+        verify(internal, times(1)).delete(deleteQuery);
+
+        assertEquals(1, deleteResult.numberOfRowsDeleted());
+        assertEquals(Collections.singleton(testTable), deleteResult.affectedTables());
+    }
+
+    private static class TestItem {
+
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResultTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResultTest.java
new file mode 100644
index 0000000..d02b3d7
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResultTest.java
@@ -0,0 +1,47 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+
+public class DeleteResultTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void nullAffectedTable() {
+        DeleteResult.newInstance(0, (String) null);
+    }
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void nullAffectedTables() {
+        DeleteResult.newInstance(0, (Set<String>) null);
+    }
+
+    @Test
+    public void numberOfRowsDeleted() {
+        final DeleteResult deleteResult = DeleteResult.newInstance(3, "test_table");
+        assertEquals(3, deleteResult.numberOfRowsDeleted());
+    }
+
+    @Test
+    public void oneAffectedTable() {
+        final DeleteResult deleteResult = DeleteResult.newInstance(2, "test_table");
+        assertEquals(Collections.singleton("test_table"), deleteResult.affectedTables());
+    }
+
+    @Test
+    public void multipleAffectedTables() {
+        final Set<String> affectedTables = new HashSet<String>();
+        affectedTables.add("table1");
+        affectedTables.add("table2");
+
+        final DeleteResult deleteResult = DeleteResult.newInstance(2, affectedTables);
+
+        assertEquals(affectedTables, deleteResult.affectedTables());
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResultsTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResultsTest.java
new file mode 100644
index 0000000..b47889d
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteResultsTest.java
@@ -0,0 +1,40 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class DeleteResultsTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void nullResults() {
+        DeleteResults.newInstance(null);
+    }
+
+    @Test
+    public void results() {
+        final Map<Object, DeleteResult> results = new HashMap<Object, DeleteResult>();
+        final DeleteResults<Object> deleteResults = DeleteResults.newInstance(results);
+        assertEquals(results, deleteResults.results());
+    }
+
+    @Test
+    public void wasDeleted() {
+        final Map<String, DeleteResult> results = new HashMap<String, DeleteResult>();
+        results.put("testString", DeleteResult.newInstance(1, "test_table"));
+
+        final DeleteResults<String> deleteResults = DeleteResults.newInstance(results);
+
+        assertTrue(deleteResults.wasDeleted("testString"));
+        assertFalse(deleteResults.wasDeleted("should not be deleted"));
+
+        assertFalse(deleteResults.wasNotDeleted("testString"));
+        assertTrue(deleteResults.wasNotDeleted("should not be deleted"));
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteStub.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteStub.java
new file mode 100644
index 0000000..75ed3f5
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/DeleteStub.java
@@ -0,0 +1,176 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.sqlite.Changes;
+import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import rx.Observable;
+import rx.functions.Action1;
+
+import static java.util.Collections.singletonMap;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@SuppressWarnings("unchecked")
+class DeleteStub {
+
+    @NonNull
+    final StorIOSQLite storIOSQLite;
+
+    @NonNull
+    private final StorIOSQLite.Internal internal;
+
+    @NonNull
+    final List<TestItem> items;
+
+    @NonNull
+    final DeleteResolver<TestItem> deleteResolver;
+
+    @NonNull
+    private final SQLiteTypeMapping<TestItem> typeMapping;
+
+    private final boolean withTypeMapping, useTransaction;
+
+    private DeleteStub(boolean withTypeMapping, boolean useTransaction, int numberOfItems) {
+        this.withTypeMapping = withTypeMapping;
+        this.useTransaction = useTransaction;
+
+        storIOSQLite = mock(StorIOSQLite.class);
+        internal = mock(StorIOSQLite.Internal.class);
+
+        items = new ArrayList<TestItem>(numberOfItems);
+
+        for (int i = 0; i < numberOfItems; i++) {
+            items.add(TestItem.newInstance());
+        }
+
+        deleteResolver = mock(DeleteResolver.class);
+
+        typeMapping = mock(SQLiteTypeMapping.class);
+
+        when(storIOSQLite.internal()).thenReturn(internal);
+        when(storIOSQLite.delete()).thenReturn(new PreparedDelete.Builder(storIOSQLite));
+        when(deleteResolver.performDelete(eq(storIOSQLite), any(TestItem.class)))
+                .thenReturn(DeleteResult.newInstance(1, TestItem.TABLE));
+
+        if (withTypeMapping) {
+            when(internal.typeMapping(TestItem.class)).thenReturn(typeMapping);
+            when(typeMapping.deleteResolver()).thenReturn(deleteResolver);
+        }
+    }
+
+    @NonNull
+    static DeleteStub newStubForMultipleObjectsWithoutTypeMappingWithoutTransaction() {
+        return new DeleteStub(false, false, 3);
+    }
+
+    @NonNull
+    static DeleteStub newStubForMultipleObjectsWithoutTypeMappingWithTransaction() {
+        return new DeleteStub(false, true, 3);
+    }
+
+    @NonNull
+    static DeleteStub newStubForMultipleObjectsWithTypeMappingWithoutTransaction() {
+        return new DeleteStub(true, false, 3);
+    }
+
+    @NonNull
+    static DeleteStub newStubForMultipleObjectsWithTypeMappingWithTransaction() {
+        return new DeleteStub(true, true, 3);
+    }
+
+    @NonNull
+    static DeleteStub newStubForOneObjectWithoutTypeMapping() {
+        return new DeleteStub(false, false, 1);
+    }
+
+    @NonNull
+    static DeleteStub newStubForOneObjectWithTypeMapping() {
+        return new DeleteStub(true, false, 1);
+    }
+
+    void verifyBehaviorForMultipleObjects(@NonNull DeleteResults<TestItem> deleteResults) {
+        verify(storIOSQLite).delete(); // Only one call to delete should occur
+
+        verify(storIOSQLite).internal(); // Only one call to internal should occur
+
+        // Number of calls to perform deletion of objects should be equals to number of items
+        verify(deleteResolver, times(items.size()))
+                .performDelete(eq(storIOSQLite), any(TestItem.class));
+
+        // Perform delete should be called for each item
+        for (TestItem item : items) {
+            verify(deleteResolver).performDelete(storIOSQLite, item);
+        }
+
+        if (withTypeMapping) {
+            // Number of calls to receive delete resolver should be equal to number of items
+            verify(internal, times(items.size())).typeMapping(TestItem.class);
+            verify(typeMapping, times(items.size())).deleteResolver();
+        }
+
+        verifyTransactionBehavior();
+        verifyNoMoreInteractions(storIOSQLite, internal, deleteResolver, typeMapping);
+    }
+
+    void verifyBehaviorForMultipleObjects(@NonNull Observable<DeleteResults<TestItem>> observable) {
+        new ObservableBehaviorChecker<DeleteResults<TestItem>>()
+                .observable(observable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<DeleteResults<TestItem>>() {
+                    @Override
+                    public void call(DeleteResults<TestItem> deleteResults) {
+                        verifyBehaviorForMultipleObjects(deleteResults);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+
+    void verifyBehaviorForOneObject(@NonNull DeleteResult deleteResult) {
+        verifyBehaviorForMultipleObjects(DeleteResults.newInstance(singletonMap(items.get(0), deleteResult)));
+    }
+
+    void verifyBehaviorForOneObject(@NonNull Observable<DeleteResult> observable) {
+        new ObservableBehaviorChecker<DeleteResult>()
+                .observable(observable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<DeleteResult>() {
+                    @Override
+                    public void call(DeleteResult deleteResult) {
+                        verifyBehaviorForOneObject(deleteResult);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+
+    private void verifyTransactionBehavior() {
+        if (useTransaction) {
+            verify(internal).beginTransaction();
+            verify(internal).setTransactionSuccessful();
+            verify(internal).endTransaction();
+
+            // Only one notification should be thrown
+            verify(internal).notifyAboutChanges(eq(Changes.newInstance(TestItem.TABLE)));
+        } else {
+            verify(internal, never()).beginTransaction();
+            verify(internal, never()).setTransactionSuccessful();
+            verify(internal, never()).endTransaction();
+
+            // Each delete should trigger notification
+            verify(internal, times(items.size()))
+                    .notifyAboutChanges(eq(Changes.newInstance(TestItem.TABLE)));
+        }
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteCollectionOfObjectsTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteCollectionOfObjectsTest.java
new file mode 100644
index 0000000..84341b6
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteCollectionOfObjectsTest.java
@@ -0,0 +1,285 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+import rx.Observable;
+import rx.observers.TestSubscriber;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(Enclosed.class)
+public class PreparedDeleteCollectionOfObjectsTest {
+
+    public static class WithoutTypeMapping {
+
+        @Test
+        public void shouldDeleteObjectsWithoutTypeMappingWithoutTransactionBlocking() {
+            final DeleteStub deleteStub
+                    = DeleteStub.newStubForMultipleObjectsWithoutTypeMappingWithoutTransaction();
+
+            final DeleteResults<TestItem> deleteResults = deleteStub.storIOSQLite
+                    .delete()
+                    .objects(deleteStub.items)
+                    .useTransaction(false)
+                    .withDeleteResolver(deleteStub.deleteResolver)
+                    .prepare()
+                    .executeAsBlocking();
+
+            deleteStub.verifyBehaviorForMultipleObjects(deleteResults);
+        }
+
+        @Test
+        public void shouldDeleteObjectsWithoutTypeMappingWithTransactionBlocking() {
+            final DeleteStub deleteStub
+                    = DeleteStub.newStubForMultipleObjectsWithoutTypeMappingWithTransaction();
+
+            final DeleteResults<TestItem> deleteResults = deleteStub.storIOSQLite
+                    .delete()
+                    .objects(deleteStub.items)
+                    .useTransaction(true)
+                    .withDeleteResolver(deleteStub.deleteResolver)
+                    .prepare()
+                    .executeAsBlocking();
+
+            deleteStub.verifyBehaviorForMultipleObjects(deleteResults);
+        }
+
+        @Test
+        public void shouldDeleteObjectsWithoutTypeMappingWithoutTransactionAsObservable() {
+            final DeleteStub deleteStub
+                    = DeleteStub.newStubForMultipleObjectsWithoutTypeMappingWithoutTransaction();
+
+            final Observable<DeleteResults<TestItem>> observable = deleteStub.storIOSQLite
+                    .delete()
+                    .objects(deleteStub.items)
+                    .useTransaction(false)
+                    .withDeleteResolver(deleteStub.deleteResolver)
+                    .prepare()
+                    .createObservable();
+
+            deleteStub.verifyBehaviorForMultipleObjects(observable);
+        }
+
+        @Test
+        public void shouldDeleteObjectsWithoutTypeMappingWithTransactionAsObservable() {
+            final DeleteStub deleteStub
+                    = DeleteStub.newStubForMultipleObjectsWithoutTypeMappingWithTransaction();
+
+            final Observable<DeleteResults<TestItem>> observable = deleteStub.storIOSQLite
+                    .delete()
+                    .objects(deleteStub.items)
+                    .useTransaction(true)
+                    .withDeleteResolver(deleteStub.deleteResolver)
+                    .prepare()
+                    .createObservable();
+
+            deleteStub.verifyBehaviorForMultipleObjects(observable);
+        }
+    }
+
+    public static class WithTypeMapping {
+
+        @Test
+        public void shouldDeleteObjectsWithTypeMappingWithoutTransactionBlocking() {
+            final DeleteStub deleteStub
+                    = DeleteStub.newStubForMultipleObjectsWithTypeMappingWithoutTransaction();
+
+            final DeleteResults<TestItem> deleteResults = deleteStub.storIOSQLite
+                    .delete()
+                    .objects(deleteStub.items)
+                    .useTransaction(false)
+                    .prepare()
+                    .executeAsBlocking();
+
+            deleteStub.verifyBehaviorForMultipleObjects(deleteResults);
+        }
+
+        @Test
+        public void shouldDeleteObjectsWithTypeMappingWithTransactionBlocking() {
+            final DeleteStub deleteStub
+                    = DeleteStub.newStubForMultipleObjectsWithTypeMappingWithTransaction();
+
+            final DeleteResults<TestItem> deleteResults = deleteStub.storIOSQLite
+                    .delete()
+                    .objects(deleteStub.items)
+                    .useTransaction(true)
+                    .prepare()
+                    .executeAsBlocking();
+
+            deleteStub.verifyBehaviorForMultipleObjects(deleteResults);
+        }
+
+        @Test
+        public void shouldDeleteObjectsWithTypeMappingWithoutTransactionObservable() {
+            final DeleteStub deleteStub
+                    = DeleteStub.newStubForMultipleObjectsWithTypeMappingWithoutTransaction();
+
+            final Observable<DeleteResults<TestItem>> observable = deleteStub.storIOSQLite
+                    .delete()
+                    .objects(deleteStub.items)
+                    .useTransaction(false)
+                    .prepare()
+                    .createObservable();
+
+            deleteStub.verifyBehaviorForMultipleObjects(observable);
+        }
+
+        @Test
+        public void shouldDeleteObjectsWithTypeMappingWithTransactionObservable() {
+            final DeleteStub deleteStub
+                    = DeleteStub.newStubForMultipleObjectsWithTypeMappingWithTransaction();
+
+            final Observable<DeleteResults<TestItem>> observable = deleteStub.storIOSQLite
+                    .delete()
+                    .objects(deleteStub.items)
+                    .useTransaction(true)
+                    .prepare()
+                    .createObservable();
+
+            deleteStub.verifyBehaviorForMultipleObjects(observable);
+        }
+    }
+
+    public static class NoTypeMappingError {
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutTransactionWithoutAffectingDbBlocking() {
+            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+            when(storIOSQLite.internal()).thenReturn(internal);
+
+            when(storIOSQLite.delete()).thenReturn(new PreparedDelete.Builder(storIOSQLite));
+
+            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
+
+            final PreparedDelete<DeleteResults<TestItem>> preparedDelete = storIOSQLite
+                    .delete()
+                    .objects(items)
+                    .useTransaction(false)
+                    .prepare();
+
+            try {
+                preparedDelete.executeAsBlocking();
+                fail();
+            } catch (IllegalStateException expected) {
+                // it's okay, no type mapping was found
+            }
+
+            verify(storIOSQLite).delete();
+            verify(storIOSQLite).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).delete(any(DeleteQuery.class));
+            verifyNoMoreInteractions(storIOSQLite, internal);
+        }
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutTransactionWithoutAffectingDbAsObservable() {
+            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+            when(storIOSQLite.internal()).thenReturn(internal);
+
+            when(storIOSQLite.delete()).thenReturn(new PreparedDelete.Builder(storIOSQLite));
+
+            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
+
+            final TestSubscriber<DeleteResults<TestItem>> testSubscriber = new TestSubscriber<DeleteResults<TestItem>>();
+
+            storIOSQLite
+                    .delete()
+                    .objects(items)
+                    .useTransaction(false)
+                    .prepare()
+                    .createObservable()
+                    .subscribe(testSubscriber);
+
+            testSubscriber.awaitTerminalEvent();
+            testSubscriber.assertNoValues();
+            testSubscriber.assertError(IllegalStateException.class);
+
+            verify(storIOSQLite).delete();
+            verify(storIOSQLite).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).delete(any(DeleteQuery.class));
+            verifyNoMoreInteractions(storIOSQLite, internal);
+        }
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithTransactionWithoutAffectingDbBlocking() {
+            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+            when(storIOSQLite.internal()).thenReturn(internal);
+
+            when(storIOSQLite.delete()).thenReturn(new PreparedDelete.Builder(storIOSQLite));
+
+            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
+
+            final PreparedDelete<DeleteResults<TestItem>> preparedDelete = storIOSQLite
+                    .delete()
+                    .objects(items)
+                    .useTransaction(true)
+                    .prepare();
+
+            try {
+                preparedDelete.executeAsBlocking();
+                fail();
+            } catch (IllegalStateException expected) {
+                // it's okay, no type mapping was found
+            }
+
+            verify(storIOSQLite).delete();
+            verify(storIOSQLite).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).delete(any(DeleteQuery.class));
+            verifyNoMoreInteractions(storIOSQLite, internal);
+        }
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithTransactionWithoutAffectingDbAsObservable() {
+            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+            when(storIOSQLite.internal()).thenReturn(internal);
+
+            when(storIOSQLite.delete()).thenReturn(new PreparedDelete.Builder(storIOSQLite));
+
+            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
+
+            final TestSubscriber<DeleteResults<TestItem>> testSubscriber = new TestSubscriber<DeleteResults<TestItem>>();
+
+            storIOSQLite
+                    .delete()
+                    .objects(items)
+                    .useTransaction(true)
+                    .prepare()
+                    .createObservable()
+                    .subscribe(testSubscriber);
+
+            testSubscriber.awaitTerminalEvent();
+            testSubscriber.assertNoValues();
+            testSubscriber.assertError(IllegalStateException.class);
+
+            verify(storIOSQLite).delete();
+            verify(storIOSQLite).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).delete(any(DeleteQuery.class));
+            verifyNoMoreInteractions(storIOSQLite, internal);
+        }
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteObjectTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteObjectTest.java
new file mode 100644
index 0000000..caacc75
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/PreparedDeleteObjectTest.java
@@ -0,0 +1,143 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.DeleteQuery;
+
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import rx.Observable;
+import rx.observers.TestSubscriber;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(Enclosed.class)
+public class PreparedDeleteObjectTest {
+
+    public static class WithoutTypeMapping {
+
+        @Test
+        public void shouldDeleteObjectWithoutTypeMappingBlocking() {
+            final DeleteStub deleteStub = DeleteStub.newStubForOneObjectWithoutTypeMapping();
+
+            final DeleteResult deleteResult = deleteStub.storIOSQLite
+                    .delete()
+                    .object(deleteStub.items.get(0))
+                    .withDeleteResolver(deleteStub.deleteResolver)
+                    .prepare()
+                    .executeAsBlocking();
+
+            deleteStub.verifyBehaviorForOneObject(deleteResult);
+        }
+
+        @Test
+        public void shouldDeleteObjectWithoutTypeMappingAsObservable() {
+            final DeleteStub deleteStub = DeleteStub.newStubForOneObjectWithoutTypeMapping();
+
+            final Observable<DeleteResult> observable = deleteStub.storIOSQLite
+                    .delete()
+                    .object(deleteStub.items.get(0))
+                    .withDeleteResolver(deleteStub.deleteResolver)
+                    .prepare()
+                    .createObservable();
+
+            deleteStub.verifyBehaviorForOneObject(observable);
+        }
+    }
+
+    public static class WithTypeMapping {
+
+        @Test
+        public void shouldDeleteObjectWithTypeMappingBlocking() {
+            final DeleteStub deleteStub = DeleteStub.newStubForOneObjectWithTypeMapping();
+
+            final DeleteResult deleteResult = deleteStub.storIOSQLite
+                    .delete()
+                    .object(deleteStub.items.get(0))
+                    .prepare()
+                    .executeAsBlocking();
+
+            deleteStub.verifyBehaviorForOneObject(deleteResult);
+        }
+
+        @Test
+        public void shouldDeleteObjectWithTypeMappingAsObservable() {
+            final DeleteStub deleteStub = DeleteStub.newStubForOneObjectWithTypeMapping();
+
+            final Observable<DeleteResult> observable = deleteStub.storIOSQLite
+                    .delete()
+                    .object(deleteStub.items.get(0))
+                    .prepare()
+                    .createObservable();
+
+            deleteStub.verifyBehaviorForOneObject(observable);
+        }
+    }
+
+    public static class NoTypeMappingError {
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingDbBlocking() {
+            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+            when(storIOSQLite.internal()).thenReturn(internal);
+
+            when(storIOSQLite.delete()).thenReturn(new PreparedDelete.Builder(storIOSQLite));
+
+            final PreparedDelete<DeleteResult> preparedDelete = storIOSQLite
+                    .delete()
+                    .object(TestItem.newInstance())
+                    .prepare();
+
+            try {
+                preparedDelete.executeAsBlocking();
+                fail();
+            } catch (IllegalStateException expected) {
+                // it's okay, no type mapping was found
+            }
+
+            verify(storIOSQLite).delete();
+            verify(storIOSQLite).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).delete(any(DeleteQuery.class));
+            verifyNoMoreInteractions(storIOSQLite, internal);
+        }
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAffectingDbAsObservable() {
+            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+            when(storIOSQLite.internal()).thenReturn(internal);
+
+            when(storIOSQLite.delete()).thenReturn(new PreparedDelete.Builder(storIOSQLite));
+
+            final TestSubscriber<DeleteResult> testSubscriber = new TestSubscriber<DeleteResult>();
+
+            storIOSQLite
+                    .delete()
+                    .object(TestItem.newInstance())
+                    .prepare()
+                    .createObservable()
+                    .subscribe(testSubscriber);
+
+            testSubscriber.awaitTerminalEvent();
+            testSubscriber.assertNoValues();
+            testSubscriber.assertError(IllegalStateException.class);
+
+            verify(storIOSQLite).delete();
+            verify(storIOSQLite).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).delete(any(DeleteQuery.class));
+            verifyNoMoreInteractions(storIOSQLite, internal);
+        }
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/TestItem.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/TestItem.java
new file mode 100644
index 0000000..171666f
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/delete/TestItem.java
@@ -0,0 +1,17 @@
+package com.pushtorefresh.storio.sqlite.operations.delete;
+
+import android.support.annotation.NonNull;
+
+class TestItem {
+
+    static final String TABLE = "test_items";
+
+    private TestItem() {
+
+    }
+
+    @NonNull
+    static TestItem newInstance() {
+        return new TestItem();
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/execute/PreparedExecuteSQLTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/execute/PreparedExecuteSQLTest.java
new file mode 100644
index 0000000..5e59926
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/execute/PreparedExecuteSQLTest.java
@@ -0,0 +1,153 @@
+package com.pushtorefresh.storio.sqlite.operations.execute;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.sqlite.Changes;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
+import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
+
+import org.junit.Test;
+
+import java.util.HashSet;
+
+import rx.Observable;
+import rx.functions.Action1;
+
+import static java.util.Arrays.asList;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class PreparedExecuteSQLTest {
+
+    @Test
+    public void executeSQLBlockingWithoutNotifications() {
+        final Stub stub = Stub.newInstanceWithoutNotification();
+
+        stub.storIOSQLite
+                .executeSQL()
+                .withQuery(stub.rawQuery)
+                .prepare()
+                .executeAsBlocking();
+
+        stub.verifyBehavior();
+    }
+
+    @Test
+    public void executeSQLBlockingWithNotification() {
+        final Stub stub = Stub.newInstanceWithNotification();
+
+        stub.storIOSQLite
+                .executeSQL()
+                .withQuery(stub.rawQuery)
+                .prepare()
+                .executeAsBlocking();
+
+        stub.verifyBehavior();
+    }
+
+    @Test
+    public void executeSQLObservableWithoutNotifications() {
+        final Stub stub = Stub.newInstanceWithoutNotification();
+
+        final Observable<Object> observable = stub.storIOSQLite
+                .executeSQL()
+                .withQuery(stub.rawQuery)
+                .prepare()
+                .createObservable();
+
+        stub.verifyBehavior(observable);
+    }
+
+    @Test
+    public void executeSQLObservableWithNotification() {
+        final Stub stub = Stub.newInstanceWithNotification();
+
+        final Observable<Object> observable = stub.storIOSQLite
+                .executeSQL()
+                .withQuery(stub.rawQuery)
+                .prepare()
+                .createObservable();
+
+        stub.verifyBehavior(observable);
+    }
+
+    static class Stub {
+
+        private final StorIOSQLite storIOSQLite;
+        private final StorIOSQLite.Internal internal;
+        private final RawQuery rawQuery;
+        private final boolean queryWithNotification;
+
+        private final String[] affectedTables = {"test_table1", "test_table2"};
+
+        @NonNull
+        public static Stub newInstanceWithoutNotification() {
+            return new Stub(false);
+        }
+
+        @NonNull
+        public static Stub newInstanceWithNotification() {
+            return new Stub(true);
+        }
+
+        private Stub(boolean queryWithNotification) {
+            this.queryWithNotification = queryWithNotification;
+
+            storIOSQLite = mock(StorIOSQLite.class);
+            internal = mock(StorIOSQLite.Internal.class);
+
+            if (queryWithNotification) {
+                rawQuery = RawQuery.builder()
+                        .query("DROP TABLE users!")
+                        .affectsTables(affectedTables)
+                        .build();
+            } else {
+                rawQuery = RawQuery.builder()
+                        .query("DROP TABLE users!")
+                        .build();
+            }
+
+            when(storIOSQLite.internal())
+                    .thenReturn(internal);
+
+            when(storIOSQLite.executeSQL())
+                    .thenReturn(new PreparedExecuteSQL.Builder(storIOSQLite));
+        }
+
+        @SuppressWarnings("unchecked")
+        void verifyBehavior() {
+            // storIOSQLite.executeSQL() should be called once
+            verify(storIOSQLite, times(1)).executeSQL();
+
+            // storIOSQLite.internal.executeSQL() should be called once for ANY RawQuery
+            verify(internal, times(1)).executeSQL(any(RawQuery.class));
+
+            // storIOSQLite.internal.executeSQL() should be called once for required RawQuery
+            verify(internal, times(1)).executeSQL(rawQuery);
+
+            if (queryWithNotification) {
+                verify(internal).notifyAboutChanges(eq(Changes.newInstance(new HashSet<String>(asList(affectedTables)))));
+            } else {
+                verify(internal, times(0)).notifyAboutChanges(any(Changes.class));
+            }
+        }
+
+        void verifyBehavior(@NonNull Observable<Object> observable) {
+            new ObservableBehaviorChecker<Object>()
+                    .observable(observable)
+                    .expectedNumberOfEmissions(1)
+                    .testAction(new Action1<Object>() {
+                        @Override
+                        public void call(Object anObject) {
+                            verifyBehavior();
+                        }
+                    })
+                    .checkBehaviorOfObservable();
+        }
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/DefaultGetResolverTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/DefaultGetResolverTest.java
new file mode 100644
index 0000000..572505f
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/DefaultGetResolverTest.java
@@ -0,0 +1,96 @@
+package com.pushtorefresh.storio.sqlite.operations.get;
+
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
+
+import org.junit.Test;
+
+import static junit.framework.Assert.assertSame;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class DefaultGetResolverTest {
+
+    @Test
+    public void rawQuery() {
+        final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+        final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+        final RawQuery rawQuery = RawQuery.builder()
+                .query("test sql")
+                .build();
+
+        final Cursor expectedCursor = mock(Cursor.class);
+
+        when(storIOSQLite.internal())
+                .thenReturn(internal);
+
+        when(internal.rawQuery(rawQuery))
+                .thenReturn(expectedCursor);
+
+        final DefaultGetResolver<TestItem> defaultGetResolver = new DefaultGetResolver<TestItem>() {
+            @NonNull
+            @Override
+            public TestItem mapFromCursor(@NonNull Cursor cursor) {
+                return mock(TestItem.class);
+            }
+        };
+
+        final Cursor actualCursor = defaultGetResolver.performGet(storIOSQLite, rawQuery);
+
+        // only one request should occur
+        verify(internal, times(1)).rawQuery(any(RawQuery.class));
+
+        // and this request should be equals to original
+        verify(internal, times(1)).rawQuery(rawQuery);
+
+        assertSame(expectedCursor, actualCursor);
+    }
+
+    @Test
+    public void query() {
+        final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+        final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+        final Query query = Query.builder()
+                .table("test_table")
+                .build();
+
+        final Cursor expectedCursor = mock(Cursor.class);
+
+        when(storIOSQLite.internal())
+                .thenReturn(internal);
+
+        when(internal.query(query))
+                .thenReturn(expectedCursor);
+
+        final DefaultGetResolver<TestItem> defaultGetResolver = new DefaultGetResolver<TestItem>() {
+            @NonNull
+            @Override
+            public TestItem mapFromCursor(@NonNull Cursor cursor) {
+                return mock(TestItem.class);
+            }
+        };
+
+        final Cursor actualCursor = defaultGetResolver.performGet(storIOSQLite, query);
+
+        // only one request should occur
+        verify(internal, times(1)).query(any(Query.class));
+
+        // and this request should be equals to original
+        verify(internal, times(1)).query(query);
+
+        assertSame(expectedCursor, actualCursor);
+    }
+
+    private static class TestItem {
+
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/GetCursorStub.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/GetCursorStub.java
new file mode 100644
index 0000000..8b9cf48
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/GetCursorStub.java
@@ -0,0 +1,132 @@
+package com.pushtorefresh.storio.sqlite.operations.get;
+
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.sqlite.Changes;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
+import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
+
+import rx.Observable;
+import rx.functions.Action1;
+
+import static java.util.Collections.singleton;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertSame;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+class GetCursorStub {
+
+    @NonNull
+    final StorIOSQLite storIOSQLite;
+
+    @NonNull
+    private final StorIOSQLite.Internal internal;
+
+    @NonNull
+    final Query query;
+
+    @NonNull
+    final RawQuery rawQuery;
+
+    @NonNull
+    final GetResolver<Cursor> getResolverForCursor;
+
+    @NonNull
+    private final Cursor cursor;
+
+    @SuppressWarnings("unchecked")
+    private GetCursorStub() {
+        storIOSQLite = mock(StorIOSQLite.class);
+        internal = mock(StorIOSQLite.Internal.class);
+
+        when(storIOSQLite.internal())
+                .thenReturn(internal);
+
+        query = mock(Query.class);
+        when(query.table()).thenReturn("test_table");
+
+        rawQuery = mock(RawQuery.class);
+        when(rawQuery.observesTables()).thenReturn(singleton("test_table"));
+
+        getResolverForCursor = mock(GetResolver.class);
+        cursor = mock(Cursor.class);
+
+        when(storIOSQLite.get())
+                .thenReturn(new PreparedGet.Builder(storIOSQLite));
+
+        when(storIOSQLite.observeChangesInTables(eq(singleton(query.table()))))
+                .thenReturn(Observable.<Changes>empty());
+
+        assertNotNull(rawQuery.observesTables());
+
+        when(storIOSQLite.observeChangesInTables(rawQuery.observesTables()))
+                .thenReturn(Observable.<Changes>empty());
+
+        when(getResolverForCursor.performGet(storIOSQLite, query))
+                .thenReturn(cursor);
+
+        when(getResolverForCursor.performGet(storIOSQLite, rawQuery))
+                .thenReturn(cursor);
+    }
+
+    @NonNull
+    static GetCursorStub newInstance() {
+        return new GetCursorStub();
+    }
+
+    void verifyQueryBehaviorForCursor(@NonNull Cursor actualCursor) {
+        assertNotNull(actualCursor);
+        verify(storIOSQLite).get();
+        verify(getResolverForCursor).performGet(storIOSQLite, query);
+        assertSame(cursor, actualCursor);
+        verifyNoMoreInteractions(storIOSQLite, internal, cursor);
+    }
+
+    void verifyQueryBehaviorForCursor(@NonNull Observable<Cursor> observable) {
+        new ObservableBehaviorChecker<Cursor>()
+                .observable(observable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<Cursor>() {
+                    @Override
+                    public void call(Cursor cursor) {
+                        // Get Operation should be subscribed to changes of tables from Query
+                        verify(storIOSQLite).observeChangesInTables(eq(singleton(query.table())));
+                        verifyQueryBehaviorForCursor(cursor);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+
+    void verifyRawQueryBehaviorForCursor(@NonNull Cursor actualCursor) {
+        assertNotNull(actualCursor);
+        verify(storIOSQLite, times(1)).get();
+        verify(getResolverForCursor, times(1)).performGet(storIOSQLite, rawQuery);
+        assertSame(cursor, actualCursor);
+        verifyNoMoreInteractions(storIOSQLite, internal, cursor);
+    }
+
+    void verifyRawQueryBehaviorForCursor(@NonNull Observable<Cursor> observable) {
+        new ObservableBehaviorChecker<Cursor>()
+                .observable(observable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<Cursor>() {
+                    @Override
+                    public void call(Cursor cursor) {
+                        // Get Operation should be subscribed to changes of tables from Query
+                        verify(storIOSQLite).observeChangesInTables(rawQuery.observesTables());
+                        verifyRawQueryBehaviorForCursor(cursor);
+                    }
+                })
+                .checkBehaviorOfObservable();
+
+        assertNotNull(rawQuery.observesTables());
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/GetObjectsStub.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/GetObjectsStub.java
new file mode 100644
index 0000000..6b83faf
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/GetObjectsStub.java
@@ -0,0 +1,226 @@
+package com.pushtorefresh.storio.sqlite.operations.get;
+
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.sqlite.Changes;
+import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
+import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import rx.Observable;
+import rx.functions.Action1;
+
+import static com.pushtorefresh.storio.test.Asserts.assertThatListIsImmutable;
+import static java.util.Collections.singleton;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+class GetObjectsStub {
+
+    @NonNull
+    final StorIOSQLite storIOSQLite;
+
+    @NonNull
+    private final StorIOSQLite.Internal internal;
+
+    @NonNull
+    final Query query;
+
+    @NonNull
+    final RawQuery rawQuery;
+
+    @NonNull
+    final GetResolver<TestItem> getResolver;
+
+    @NonNull
+    private final Cursor cursor;
+
+    @NonNull
+    final List<TestItem> items;
+
+    @NonNull
+    private final SQLiteTypeMapping<TestItem> typeMapping;
+
+    private final boolean withTypeMapping;
+
+    @SuppressWarnings("unchecked")
+    private GetObjectsStub(boolean withTypeMapping) {
+        this.withTypeMapping = withTypeMapping;
+
+        storIOSQLite = mock(StorIOSQLite.class);
+        internal = mock(StorIOSQLite.Internal.class);
+
+        when(storIOSQLite.internal())
+                .thenReturn(internal);
+
+        query = mock(Query.class);
+        when(query.table()).thenReturn("test_table");
+
+        rawQuery = mock(RawQuery.class);
+        when(rawQuery.observesTables()).thenReturn(singleton("test_table"));
+
+        getResolver = mock(GetResolver.class);
+        cursor = mock(Cursor.class);
+
+        items = new ArrayList<TestItem>();
+        items.add(new TestItem());
+        items.add(new TestItem());
+        items.add(new TestItem());
+
+        when(cursor.getCount())
+                .thenReturn(items.size());
+
+        when(cursor.moveToNext()).thenAnswer(new Answer<Boolean>() {
+            int invocationsCount = 0;
+
+            @Override
+            public Boolean answer(InvocationOnMock invocation) throws Throwable {
+                return invocationsCount++ < items.size();
+            }
+        });
+
+        when(storIOSQLite.get())
+                .thenReturn(new PreparedGet.Builder(storIOSQLite));
+
+        when(storIOSQLite.observeChangesInTables(eq(singleton(query.table()))))
+                .thenReturn(Observable.<Changes>empty());
+
+        assertNotNull(rawQuery.observesTables());
+
+        when(storIOSQLite.observeChangesInTables(rawQuery.observesTables()))
+                .thenReturn(Observable.<Changes>empty());
+
+        when(getResolver.performGet(storIOSQLite, query))
+                .thenReturn(cursor);
+
+        when(getResolver.performGet(storIOSQLite, rawQuery))
+                .thenReturn(cursor);
+
+        when(getResolver.mapFromCursor(cursor))
+                .thenAnswer(new Answer<TestItem>() {
+                    int invocationsCount = 0;
+
+                    @Override
+                    public TestItem answer(InvocationOnMock invocation) throws Throwable {
+                        final TestItem testItem = items.get(invocationsCount);
+                        invocationsCount++;
+                        return testItem;
+                    }
+                });
+
+        typeMapping = mock(SQLiteTypeMapping.class);
+
+        if (withTypeMapping) {
+            when(internal.typeMapping(TestItem.class)).thenReturn(typeMapping);
+            when(typeMapping.getResolver()).thenReturn(getResolver);
+        }
+    }
+
+    @NonNull
+    static GetObjectsStub newInstanceWithoutTypeMapping() {
+        return new GetObjectsStub(false);
+    }
+
+    @NonNull
+    static GetObjectsStub newInstanceWithTypeMapping() {
+        return new GetObjectsStub(true);
+    }
+
+    void verifyQueryBehavior(@NonNull List<TestItem> actualList) {
+        // should be called once
+        verify(storIOSQLite).get();
+
+        // should be called only once
+        verify(getResolver).performGet(storIOSQLite, query);
+
+        // should be called same number of times as number of items
+        verify(getResolver, times(items.size())).mapFromCursor(cursor);
+
+        // should be called only once because of Performance!
+        verify(cursor).getCount();
+
+        // should be called same number of times as count of items in cursor + 1 (last -> false)
+        verify(cursor, times(items.size() + 1)).moveToNext();
+
+        // cursor must be closed!
+        verify(cursor, times(1)).close();
+
+        // actual items should be equals to expected
+        assertEquals(items, actualList);
+
+        // list should be immutable!
+        assertThatListIsImmutable(actualList);
+
+        if (withTypeMapping) {
+            // should be called only once because of Performance!
+            verify(storIOSQLite).internal();
+
+            // should be called only once because of Performance!
+            verify(internal).typeMapping(TestItem.class);
+
+            // should be called only once because of Performance!
+            verify(typeMapping).getResolver();
+        }
+
+        verifyNoMoreInteractions(storIOSQLite, internal, cursor);
+    }
+
+    void verifyQueryBehavior(@NonNull Observable<List<TestItem>> observable) {
+        new ObservableBehaviorChecker<List<TestItem>>()
+                .observable(observable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<List<TestItem>>() {
+                    @Override
+                    public void call(List<TestItem> testItems) {
+                        // Get Operation should be subscribed to changes of tables from query
+                        verify(storIOSQLite).observeChangesInTables(eq(singleton(query.table())));
+
+                        verifyQueryBehavior(testItems);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+
+    void verifyRawQueryBehavior(@NonNull List<TestItem> actualList) {
+        assertNotNull(actualList);
+        verify(storIOSQLite, times(1)).get();
+        verify(getResolver, times(1)).performGet(storIOSQLite, rawQuery);
+        verify(getResolver, times(items.size())).mapFromCursor(cursor);
+        verify(cursor, times(1)).close();
+        assertEquals(items, actualList);
+        assertThatListIsImmutable(actualList);
+    }
+
+    void verifyRawQueryBehavior(@NonNull Observable<List<TestItem>> observable) {
+        new ObservableBehaviorChecker<List<TestItem>>()
+                .observable(observable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<List<TestItem>>() {
+                    @Override
+                    public void call(List<TestItem> testItems) {
+                        // Get Operation should be subscribed to changes of tables from query
+                        verify(storIOSQLite).observeChangesInTables(rawQuery.observesTables());
+
+                        verifyRawQueryBehavior(testItems);
+                    }
+                })
+                .checkBehaviorOfObservable();
+
+        assertNotNull(rawQuery.observesTables());
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetCursorTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetCursorTest.java
new file mode 100644
index 0000000..a0c0718
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetCursorTest.java
@@ -0,0 +1,74 @@
+package com.pushtorefresh.storio.sqlite.operations.get;
+
+import android.database.Cursor;
+
+import org.junit.Test;
+
+import rx.Observable;
+
+public class PreparedGetCursorTest {
+
+    @Test
+    public void shouldGetCursorWithQueryBlocking() {
+        final GetCursorStub getStub = GetCursorStub.newInstance();
+
+        final Cursor cursor = getStub.storIOSQLite
+                .get()
+                .cursor()
+                .withQuery(getStub.query)
+                .withGetResolver(getStub.getResolverForCursor)
+                .prepare()
+                .executeAsBlocking();
+
+        getStub.verifyQueryBehaviorForCursor(cursor);
+    }
+
+
+    @Test
+    public void shouldGetCursorWithQueryAsObservable() {
+        final GetCursorStub getStub = GetCursorStub.newInstance();
+
+        final Observable<Cursor> cursorObservable = getStub.storIOSQLite
+                .get()
+                .cursor()
+                .withQuery(getStub.query)
+                .withGetResolver(getStub.getResolverForCursor)
+                .prepare()
+                .createObservable()
+                .take(1);
+
+        getStub.verifyQueryBehaviorForCursor(cursorObservable);
+    }
+
+
+    @Test
+    public void shouldGetCursorWithRawQueryBlocking() {
+        final GetCursorStub getStub = GetCursorStub.newInstance();
+
+        final Cursor cursor = getStub.storIOSQLite
+                .get()
+                .cursor()
+                .withQuery(getStub.rawQuery)
+                .withGetResolver(getStub.getResolverForCursor)
+                .prepare()
+                .executeAsBlocking();
+
+        getStub.verifyRawQueryBehaviorForCursor(cursor);
+    }
+
+    @Test
+    public void shouldGetCursorWithRawQueryAsObservable() {
+        final GetCursorStub getStub = GetCursorStub.newInstance();
+
+        final Observable<Cursor> cursorObservable = getStub.storIOSQLite
+                .get()
+                .cursor()
+                .withQuery(getStub.rawQuery)
+                .withGetResolver(getStub.getResolverForCursor)
+                .prepare()
+                .createObservable()
+                .take(1);
+
+        getStub.verifyRawQueryBehaviorForCursor(cursorObservable);
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetListOfObjectsTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetListOfObjectsTest.java
new file mode 100644
index 0000000..c461bd3
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/PreparedGetListOfObjectsTest.java
@@ -0,0 +1,276 @@
+package com.pushtorefresh.storio.sqlite.operations.get;
+
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.RawQuery;
+
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.Set;
+
+import rx.Observable;
+import rx.observers.TestSubscriber;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anySet;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(Enclosed.class)
+public class PreparedGetListOfObjectsTest {
+
+    public static class WithoutTypeMapping {
+
+        @Test
+        public void shouldGetListOfObjectsByQueryWithoutTypeMappingBlocking() {
+            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithoutTypeMapping();
+
+            final List<TestItem> testItems = getStub.storIOSQLite
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(getStub.query)
+                    .withGetResolver(getStub.getResolver)
+                    .prepare()
+                    .executeAsBlocking();
+
+            getStub.verifyQueryBehavior(testItems);
+        }
+
+        @Test
+        public void shouldGetListOfObjectsByQueryWithoutTypeMappingAsObservable() {
+            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithoutTypeMapping();
+
+            final Observable<List<TestItem>> testItemsObservable = getStub.storIOSQLite
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(getStub.query)
+                    .withGetResolver(getStub.getResolver)
+                    .prepare()
+                    .createObservable()
+                    .take(1);
+
+            getStub.verifyQueryBehavior(testItemsObservable);
+        }
+
+        @Test
+        public void shouldGetListOfObjectsByRawQueryWithoutTypeMappingBlocking() {
+            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithoutTypeMapping();
+
+            final List<TestItem> testItems = getStub.storIOSQLite
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(getStub.rawQuery)
+                    .withGetResolver(getStub.getResolver)
+                    .prepare()
+                    .executeAsBlocking();
+
+            getStub.verifyRawQueryBehavior(testItems);
+        }
+
+        @Test
+        public void shouldGetListOfObjectsByRawQueryWithoutTypeMappingAsObservable() {
+            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithoutTypeMapping();
+
+            final Observable<List<TestItem>> testItemsObservable = getStub.storIOSQLite
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(getStub.rawQuery)
+                    .withGetResolver(getStub.getResolver)
+                    .prepare()
+                    .createObservable()
+                    .take(1);
+
+            getStub.verifyRawQueryBehavior(testItemsObservable);
+        }
+    }
+
+    public static class WithTypeMapping {
+
+        @Test
+        public void shouldGetListOfObjectsByQueryWithTypeMappingBlocking() {
+            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithTypeMapping();
+
+            final List<TestItem> testItems = getStub.storIOSQLite
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(getStub.query)
+                    .prepare()
+                    .executeAsBlocking();
+
+            getStub.verifyQueryBehavior(testItems);
+        }
+
+        @Test
+        public void shouldGetListOfObjectsByQueryWithTypeMappingAsObservable() {
+            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithTypeMapping();
+
+            final Observable<List<TestItem>> testItemsObservable = getStub.storIOSQLite
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(getStub.query)
+                    .prepare()
+                    .createObservable()
+                    .take(1);
+
+            getStub.verifyQueryBehavior(testItemsObservable);
+        }
+
+        @Test
+        public void shouldGetListOfObjectsByRawQueryWithTypeMappingBlocking() {
+            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithTypeMapping();
+
+            final List<TestItem> testItems = getStub.storIOSQLite
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(getStub.rawQuery)
+                    .prepare()
+                    .executeAsBlocking();
+
+            getStub.verifyRawQueryBehavior(testItems);
+        }
+
+        @Test
+        public void shouldGetListOfObjectsByRawQueryWithTypeMappingAsObservable() {
+            final GetObjectsStub getStub = GetObjectsStub.newInstanceWithTypeMapping();
+
+            final Observable<List<TestItem>> testItemsObservable = getStub.storIOSQLite
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(getStub.rawQuery)
+                    .prepare()
+                    .createObservable()
+                    .take(1);
+
+            getStub.verifyRawQueryBehavior(testItemsObservable);
+        }
+    }
+
+    public static class NoTypeMappingError {
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAccessingDbWithQueryBlocking() {
+            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+            when(storIOSQLite.get()).thenReturn(new PreparedGet.Builder(storIOSQLite));
+            when(storIOSQLite.internal()).thenReturn(internal);
+
+            final PreparedGet<List<TestItem>> preparedGet = storIOSQLite
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(mock(Query.class))
+                    .prepare();
+
+            try {
+                preparedGet.executeAsBlocking();
+                fail();
+            } catch (IllegalStateException expected) {
+                // it's okay, no type mapping was found
+            }
+
+            verify(storIOSQLite).get();
+            verify(storIOSQLite).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).query(any(Query.class));
+            verifyNoMoreInteractions(storIOSQLite, internal);
+        }
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAccessingDbWithRawQueryBlocking() {
+            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+            when(storIOSQLite.get()).thenReturn(new PreparedGet.Builder(storIOSQLite));
+            when(storIOSQLite.internal()).thenReturn(internal);
+
+            final PreparedGet<List<TestItem>> preparedGet = storIOSQLite
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(mock(RawQuery.class))
+                    .prepare();
+
+            try {
+                preparedGet.executeAsBlocking();
+                fail();
+            } catch (IllegalStateException expected) {
+                // it's okay, no type mapping was found
+            }
+
+            verify(storIOSQLite).get();
+            verify(storIOSQLite).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).rawQuery(any(RawQuery.class));
+            verifyNoMoreInteractions(storIOSQLite, internal);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAccessingDbWithQueryAsObservable() {
+            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+            when(storIOSQLite.get()).thenReturn(new PreparedGet.Builder(storIOSQLite));
+            when(storIOSQLite.internal()).thenReturn(internal);
+            when(storIOSQLite.observeChangesInTables(any(Set.class)))
+                    .thenReturn(Observable.empty());
+
+            final TestSubscriber<List<TestItem>> testSubscriber = new TestSubscriber<List<TestItem>>();
+
+            storIOSQLite
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(mock(Query.class))
+                    .prepare()
+                    .createObservable()
+                    .subscribe(testSubscriber);
+
+            testSubscriber.awaitTerminalEvent();
+            testSubscriber.assertNoValues();
+            testSubscriber.assertError(IllegalStateException.class);
+
+            verify(storIOSQLite).get();
+            verify(storIOSQLite).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).query(any(Query.class));
+            verify(storIOSQLite).observeChangesInTables(anySet());
+            verifyNoMoreInteractions(storIOSQLite, internal);
+        }
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutAccessingDbWithRawQueryAsObservable() {
+            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+            when(storIOSQLite.get()).thenReturn(new PreparedGet.Builder(storIOSQLite));
+            when(storIOSQLite.internal()).thenReturn(internal);
+
+            final TestSubscriber<List<TestItem>> testSubscriber = new TestSubscriber<List<TestItem>>();
+
+            storIOSQLite
+                    .get()
+                    .listOfObjects(TestItem.class)
+                    .withQuery(mock(RawQuery.class))
+                    .prepare()
+                    .createObservable()
+                    .subscribe(testSubscriber);
+
+            testSubscriber.awaitTerminalEvent();
+            testSubscriber.assertNoValues();
+            testSubscriber.assertError(IllegalStateException.class);
+
+            verify(storIOSQLite).get();
+            verify(storIOSQLite).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).rawQuery(any(RawQuery.class));
+            verifyNoMoreInteractions(storIOSQLite, internal);
+        }
+    }
+
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/TestItem.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/TestItem.java
new file mode 100644
index 0000000..bd7c1ae
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/get/TestItem.java
@@ -0,0 +1,29 @@
+package com.pushtorefresh.storio.sqlite.operations.get;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+class TestItem {
+
+    private static final AtomicLong COUNTER = new AtomicLong(0);
+
+    private Long id = COUNTER.incrementAndGet();
+
+    public Long getId() {
+        return id;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        TestItem testItem = (TestItem) o;
+
+        return !(id != null ? !id.equals(testItem.id) : testItem.id != null);
+    }
+
+    @Override
+    public int hashCode() {
+        return id != null ? id.hashCode() : 0;
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/DefaultPutResolverTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/DefaultPutResolverTest.java
new file mode 100644
index 0000000..67829d1
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/DefaultPutResolverTest.java
@@ -0,0 +1,267 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.InsertQuery;
+import com.pushtorefresh.storio.sqlite.queries.Query;
+import com.pushtorefresh.storio.sqlite.queries.UpdateQuery;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import rx.functions.Func1;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class DefaultPutResolverTest {
+
+    /**
+     * Verifies behavior of {@link DefaultPutResolver} for "insert"
+     */
+    @Test
+    public void insert() {
+        final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+        final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+        final TestItem testItem = new TestItem(null); // item without id, should be inserted
+
+        when(storIOSQLite.internal())
+                .thenReturn(internal);
+
+        final Long expectedInsertedId = 24L;
+
+        final Query expectedQuery = Query.builder()
+                .table(TestItem.TABLE)
+                .where(TestItem.COLUMN_ID + " = ?")
+                .whereArgs(testItem.getId())
+                .build();
+
+        final Cursor cursor = mock(Cursor.class);
+
+        when(internal.query(eq(expectedQuery)))
+                .thenReturn(cursor);
+
+        when(cursor.getCount())
+                .thenReturn(0); // No results -> insert should be performed
+
+        when(internal.insert(any(InsertQuery.class), any(ContentValues.class)))
+                .thenReturn(expectedInsertedId);
+
+        final InsertQuery expectedInsertQuery = InsertQuery.builder()
+                .table(TestItem.TABLE)
+                .nullColumnHack(null)
+                .build();
+
+        final PutResolver<TestItem> putResolver = new DefaultPutResolver<TestItem>() {
+            @NonNull
+            @Override
+            protected InsertQuery mapToInsertQuery(@NonNull TestItem object) {
+                return expectedInsertQuery;
+            }
+
+            @NonNull
+            @Override
+            protected UpdateQuery mapToUpdateQuery(@NonNull TestItem object) {
+                return UpdateQuery.builder()
+                        .table(TestItem.TABLE)
+                        .where(TestItem.COLUMN_ID + " = ?")
+                        .whereArgs(object.getId())
+                        .build();
+            }
+
+            @NonNull
+            @Override
+            protected ContentValues mapToContentValues(@NonNull TestItem object) {
+                return TestItem.MAP_TO_CONTENT_VALUES.call(object);
+            }
+        };
+
+        final ContentValues expectedContentValues = TestItem.MAP_TO_CONTENT_VALUES.call(testItem);
+
+        // Performing Put that should "insert"
+        final PutResult putResult = putResolver.performPut(storIOSQLite, testItem);
+
+        verify(internal, times(1)).beginTransaction();
+        verify(internal, times(1)).setTransactionSuccessful();
+        verify(internal, times(1)).endTransaction();
+
+        // checks that it asks db for results
+        verify(internal, times(1)).query(eq(expectedQuery));
+
+        // checks that cursor was closed
+        verify(cursor, times(1)).close();
+
+        // only one query should occur
+        verify(internal, times(1)).query(any(Query.class));
+
+        // checks that required insert was performed
+        verify(internal, times(1)).insert(eq(expectedInsertQuery), eq(expectedContentValues));
+
+        // only one insert should occur
+        verify(internal, times(1)).insert(any(InsertQuery.class), any(ContentValues.class));
+
+        // no updates should occur
+        verify(internal, times(0)).update(any(UpdateQuery.class), any(ContentValues.class));
+
+        // put result checks
+        assertTrue(putResult.wasInserted());
+        assertFalse(putResult.wasUpdated());
+
+        assertEquals(expectedInsertedId, putResult.insertedId());
+        assertNull(putResult.numberOfRowsUpdated());
+    }
+
+    /**
+     * Verifies behavior of {@link DefaultPutResolver} for "update"
+     */
+    @Test
+    public void update() {
+        final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+        final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+        final TestItem testItem = new TestItem(null); // item with some id, should be updated
+
+        when(storIOSQLite.internal())
+                .thenReturn(internal);
+
+        final Query expectedQuery = Query.builder()
+                .table(TestItem.TABLE)
+                .where(TestItem.COLUMN_ID + " = ?")
+                .whereArgs(testItem.getId())
+                .build();
+
+        final Cursor cursor = mock(Cursor.class);
+
+        when(internal.query(eq(expectedQuery)))
+                .thenReturn(cursor);
+
+        when(cursor.getCount())
+                .thenReturn(1); // Some rows already in db -> update should be performed
+
+        final Integer expectedNumberOfRowsUpdated = 1;
+
+        when(internal.update(any(UpdateQuery.class), any(ContentValues.class)))
+                .thenReturn(expectedNumberOfRowsUpdated);
+
+        final UpdateQuery expectedUpdateQuery = UpdateQuery.builder()
+                .table(TestItem.TABLE)
+                .where(TestItem.COLUMN_ID + " = ?")
+                .whereArgs(testItem.getId())
+                .build();
+
+        final PutResolver<TestItem> putResolver = new DefaultPutResolver<TestItem>() {
+            @NonNull
+            @Override
+            protected InsertQuery mapToInsertQuery(@NonNull TestItem object) {
+                fail("Should not be called");
+                return null;
+            }
+
+            @NonNull
+            @Override
+            protected UpdateQuery mapToUpdateQuery(@NonNull TestItem object) {
+                return UpdateQuery.builder()
+                        .table(TestItem.TABLE)
+                        .where(TestItem.COLUMN_ID + " = ?")
+                        .whereArgs(object.getId())
+                        .build();
+            }
+
+            @NonNull
+            @Override
+            protected ContentValues mapToContentValues(@NonNull TestItem object) {
+                return TestItem.MAP_TO_CONTENT_VALUES.call(object);
+            }
+        };
+
+        final ContentValues expectedContentValues = TestItem.MAP_TO_CONTENT_VALUES.call(testItem);
+
+        // Performing Put that should "update"
+        final PutResult putResult = putResolver.performPut(storIOSQLite, testItem);
+
+        verify(internal, times(1)).beginTransaction();
+        verify(internal, times(1)).setTransactionSuccessful();
+        verify(internal, times(1)).endTransaction();
+
+        // checks that it asks db for results
+        verify(internal, times(1)).query(eq(expectedQuery));
+
+        // checks that cursor was closed
+        verify(cursor, times(1)).close();
+
+        // only one query should occur
+        verify(internal, times(1)).query(any(Query.class));
+
+        // checks that required update was performed
+        verify(internal, times(1)).update(eq(expectedUpdateQuery), eq(expectedContentValues));
+
+        // only one update should occur
+        verify(internal, times(1)).update(any(UpdateQuery.class), any(ContentValues.class));
+
+        // no inserts should occur
+        verify(internal, times(0)).insert(any(InsertQuery.class), any(ContentValues.class));
+
+        // put result checks
+        assertFalse(putResult.wasInserted());
+        assertTrue(putResult.wasUpdated());
+
+        assertEquals(expectedNumberOfRowsUpdated, putResult.numberOfRowsUpdated());
+        assertNull(putResult.insertedId());
+    }
+
+    private static class TestItem {
+
+        final static String TABLE = "someTable";
+        final static String COLUMN_ID = "customIdColumnName";
+        @Nullable
+        private final Long id;
+        static final Func1<TestItem, ContentValues> MAP_TO_CONTENT_VALUES = new Func1<TestItem, ContentValues>() {
+
+            // ContentValues should be mocked for usage in tests (damn you Android...)
+            // but we can not mock equals() method
+            // so, we will return SAME ContentValues for object and assertEquals() will pass
+            @NonNull
+            private final Map<TestItem, ContentValues> map = new HashMap<TestItem, ContentValues>();
+
+            @NonNull
+            @Override
+            public ContentValues call(@NonNull TestItem testItem) {
+                if (map.containsKey(testItem)) {
+                    return map.get(testItem);
+                } else {
+                    final ContentValues contentValues = mock(ContentValues.class);
+
+                    when(contentValues.get(COLUMN_ID))
+                            .thenReturn(testItem.id);
+
+                    map.put(testItem, contentValues); // storing pair of mapping
+
+                    return contentValues;
+                }
+            }
+        };
+
+        TestItem(@Nullable Long id) {
+            this.id = id;
+        }
+
+        @Nullable
+        Long getId() {
+            return id;
+        }
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutCollectionOfObjectsTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutCollectionOfObjectsTest.java
new file mode 100644
index 0000000..b43128e
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutCollectionOfObjectsTest.java
@@ -0,0 +1,292 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.content.ContentValues;
+
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.sqlite.queries.InsertQuery;
+import com.pushtorefresh.storio.sqlite.queries.UpdateQuery;
+
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+import rx.Observable;
+import rx.observers.TestSubscriber;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(Enclosed.class)
+public class PreparedPutCollectionOfObjectsTest {
+
+    public static class WithoutTypeMapping {
+
+        @Test
+        public void shouldPutObjectsWithoutTypeMappingWithoutTransactionBlocking() {
+            final PutObjectsStub putStub
+                    = PutObjectsStub.newPutStubForMultipleObjectsWithoutTypeMappingWithoutTransaction();
+
+            final PutResults<TestItem> putResults = putStub.storIOSQLite
+                    .put()
+                    .objects(putStub.items)
+                    .useTransaction(false)
+                    .withPutResolver(putStub.putResolver)
+                    .prepare()
+                    .executeAsBlocking();
+
+            putStub.verifyBehaviorForMultipleObjects(putResults);
+        }
+
+        @Test
+        public void shouldPutObjectsWithoutTypeMappingWithTransactionBlocking() {
+            final PutObjectsStub putStub
+                    = PutObjectsStub.newPutStubForMultipleObjectsWithoutTypeMappingWithTransaction();
+
+            final PutResults<TestItem> putResults = putStub.storIOSQLite
+                    .put()
+                    .objects(putStub.items)
+                    .useTransaction(true)
+                    .withPutResolver(putStub.putResolver)
+                    .prepare()
+                    .executeAsBlocking();
+
+            putStub.verifyBehaviorForMultipleObjects(putResults);
+        }
+
+        @Test
+        public void shouldPutObjectsWithoutTypeMappingWithoutTransactionAsObservable() {
+            final PutObjectsStub putStub
+                    = PutObjectsStub.newPutStubForMultipleObjectsWithoutTypeMappingWithoutTransaction();
+
+            final Observable<PutResults<TestItem>> observable = putStub.storIOSQLite
+                    .put()
+                    .objects(putStub.items)
+                    .useTransaction(false)
+                    .withPutResolver(putStub.putResolver)
+                    .prepare()
+                    .createObservable();
+
+            putStub.verifyBehaviorForMultipleObjects(observable);
+        }
+
+        @Test
+        public void shouldPutObjectsWithoutTypeMappingWithTransactionAsObservable() {
+            final PutObjectsStub putStub
+                    = PutObjectsStub.newPutStubForMultipleObjectsWithoutTypeMappingWithTransaction();
+
+            final Observable<PutResults<TestItem>> observable = putStub.storIOSQLite
+                    .put()
+                    .objects(putStub.items)
+                    .useTransaction(true)
+                    .withPutResolver(putStub.putResolver)
+                    .prepare()
+                    .createObservable();
+
+            putStub.verifyBehaviorForMultipleObjects(observable);
+        }
+    }
+
+    public static class WithTypeMapping {
+
+        @Test
+        public void shouldPutObjectsWithTypeMappingWithoutTransactionBlocking() {
+            final PutObjectsStub putStub
+                    = PutObjectsStub.newPutStubForMultipleObjectsWithTypeMappingWithoutTransaction();
+
+            final PutResults<TestItem> putResults = putStub.storIOSQLite
+                    .put()
+                    .objects(putStub.items)
+                    .useTransaction(false)
+                    .prepare()
+                    .executeAsBlocking();
+
+            putStub.verifyBehaviorForMultipleObjects(putResults);
+        }
+
+        @Test
+        public void shouldPutObjectsWithTypeMappingWithTransactionBlocking() {
+            final PutObjectsStub putStub
+                    = PutObjectsStub.newPutStubForMultipleObjectsWithTypeMappingWithTransaction();
+
+            final PutResults<TestItem> putResults = putStub.storIOSQLite
+                    .put()
+                    .objects(putStub.items)
+                    .useTransaction(true)
+                    .prepare()
+                    .executeAsBlocking();
+
+            putStub.verifyBehaviorForMultipleObjects(putResults);
+        }
+
+        @Test
+        public void shouldPutObjectsWithTypeMappingWithoutTransactionAsObservable() {
+            final PutObjectsStub putStub
+                    = PutObjectsStub.newPutStubForMultipleObjectsWithTypeMappingWithoutTransaction();
+
+            final Observable<PutResults<TestItem>> observable = putStub.storIOSQLite
+                    .put()
+                    .objects(putStub.items)
+                    .useTransaction(false)
+                    .prepare()
+                    .createObservable();
+
+            putStub.verifyBehaviorForMultipleObjects(observable);
+        }
+
+        @Test
+        public void shouldPutObjectsWithTypeMappingWithTransactionAsObservable() {
+            final PutObjectsStub putStub
+                    = PutObjectsStub.newPutStubForMultipleObjectsWithTypeMappingWithTransaction();
+
+            final Observable<PutResults<TestItem>> observable = putStub.storIOSQLite
+                    .put()
+                    .objects(putStub.items)
+                    .useTransaction(true)
+                    .prepare()
+                    .createObservable();
+
+            putStub.verifyBehaviorForMultipleObjects(observable);
+        }
+    }
+
+    public static class NoTypeMappingError {
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutTransactionWithoutAffectingDbBlocking() {
+            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+            when(storIOSQLite.internal()).thenReturn(internal);
+
+            when(storIOSQLite.put()).thenReturn(new PreparedPut.Builder(storIOSQLite));
+
+            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
+
+            final PreparedPut<PutResults<TestItem>> preparedPut = storIOSQLite
+                    .put()
+                    .objects(items)
+                    .useTransaction(false)
+                    .prepare();
+
+            try {
+                preparedPut.executeAsBlocking();
+                fail();
+            } catch (IllegalStateException expected) {
+                // it's okay, no type mapping was found
+            }
+
+            verify(storIOSQLite).put();
+            verify(storIOSQLite).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
+            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
+            verifyNoMoreInteractions(storIOSQLite, internal);
+        }
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithoutTransactionWithoutAffectingDbAsObservable() {
+            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+            when(storIOSQLite.internal()).thenReturn(internal);
+
+            when(storIOSQLite.put()).thenReturn(new PreparedPut.Builder(storIOSQLite));
+
+            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
+
+            final TestSubscriber<PutResults<TestItem>> testSubscriber = new TestSubscriber<PutResults<TestItem>>();
+
+            storIOSQLite
+                    .put()
+                    .objects(items)
+                    .useTransaction(false)
+                    .prepare()
+                    .createObservable()
+                    .subscribe(testSubscriber);
+
+            testSubscriber.awaitTerminalEvent();
+            testSubscriber.assertNoValues();
+            testSubscriber.assertError(IllegalStateException.class);
+
+            verify(storIOSQLite).put();
+            verify(storIOSQLite).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
+            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
+            verifyNoMoreInteractions(storIOSQLite, internal);
+        }
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithTransactionWithoutAffectingDbBlocking() {
+            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+            when(storIOSQLite.internal()).thenReturn(internal);
+
+            when(storIOSQLite.put()).thenReturn(new PreparedPut.Builder(storIOSQLite));
+
+            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
+
+            final PreparedPut<PutResults<TestItem>> preparedPut = storIOSQLite
+                    .put()
+                    .objects(items)
+                    .useTransaction(true)
+                    .prepare();
+
+            try {
+                preparedPut.executeAsBlocking();
+                fail();
+            } catch (IllegalStateException expected) {
+                // it's okay, no type mapping was found
+            }
+
+            verify(storIOSQLite).put();
+            verify(storIOSQLite).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
+            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
+            verifyNoMoreInteractions(storIOSQLite, internal);
+        }
+
+        @Test
+        public void shouldThrowExceptionIfNoTypeMappingWasFoundWithTransactionWithoutAffectingDbAsObservable() {
+            final StorIOSQLite storIOSQLite = mock(StorIOSQLite.class);
+            final StorIOSQLite.Internal internal = mock(StorIOSQLite.Internal.class);
+
+            when(storIOSQLite.internal()).thenReturn(internal);
+
+            when(storIOSQLite.put()).thenReturn(new PreparedPut.Builder(storIOSQLite));
+
+            final List<TestItem> items = asList(TestItem.newInstance(), TestItem.newInstance());
+
+            final TestSubscriber<PutResults<TestItem>> testSubscriber = new TestSubscriber<PutResults<TestItem>>();
+
+            storIOSQLite
+                    .put()
+                    .objects(items)
+                    .useTransaction(true)
+                    .prepare()
+                    .createObservable()
+                    .subscribe(testSubscriber);
+
+            testSubscriber.awaitTerminalEvent();
+            testSubscriber.assertNoValues();
+            testSubscriber.assertError(IllegalStateException.class);
+
+            verify(storIOSQLite).put();
+            verify(storIOSQLite).internal();
+            verify(internal).typeMapping(TestItem.class);
+            verify(internal, never()).insert(any(InsertQuery.class), any(ContentValues.class));
+            verify(internal, never()).update(any(UpdateQuery.class), any(ContentValues.class));
+            verifyNoMoreInteractions(storIOSQLite, internal);
+        }
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValuesIterableTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValuesIterableTest.java
new file mode 100644
index 0000000..3931699
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValuesIterableTest.java
@@ -0,0 +1,70 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.content.ContentValues;
+
+import org.junit.Test;
+
+import rx.Observable;
+
+public class PreparedPutContentValuesIterableTest {
+
+    @Test
+    public void putMultipleBlockingWithTransaction() {
+        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForMultipleContentValues(true);
+
+        final PutResults<ContentValues> putResults = putStub.storIOSQLite
+                .put()
+                .contentValues(putStub.contentValues)
+                .withPutResolver(putStub.putResolver)
+                .useTransaction(true)
+                .prepare()
+                .executeAsBlocking();
+
+        putStub.verifyBehaviorForMultipleContentValues(putResults);
+    }
+
+    @Test
+    public void putMultipleObservableWithTransaction() {
+        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForMultipleContentValues(true);
+
+        final Observable<PutResults<ContentValues>> putResultsObservable = putStub.storIOSQLite
+                .put()
+                .contentValues(putStub.contentValues)
+                .withPutResolver(putStub.putResolver)
+                .useTransaction(true)
+                .prepare()
+                .createObservable();
+
+        putStub.verifyBehaviorForMultipleContentValues(putResultsObservable);
+    }
+
+    @Test
+    public void putMultipleBlockingWithoutTransaction() {
+        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForMultipleContentValues(false);
+
+        final PutResults<ContentValues> putResults = putStub.storIOSQLite
+                .put()
+                .contentValues(putStub.contentValues)
+                .withPutResolver(putStub.putResolver)
+                .useTransaction(false)
+                .prepare()
+                .executeAsBlocking();
+
+        putStub.verifyBehaviorForMultipleContentValues(putResults);
+    }
+
+    @Test
+    public void putMultipleObservableWithoutTransaction() {
+        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForMultipleContentValues(false);
+
+        final Observable<PutResults<ContentValues>> putResultsObservable = putStub.storIOSQLite
+                .put()
+                .contentValues(putStub.contentValues)
+                .withPutResolver(putStub.putResolver)
+                .useTransaction(false)
+                .prepare()
+                .createObservable();
+
+        putStub.verifyBehaviorForMultipleContentValues(putResultsObservable);
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValuesTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValuesTest.java
new file mode 100644
index 0000000..2e61742
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutContentValuesTest.java
@@ -0,0 +1,36 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import org.junit.Test;
+
+import rx.Observable;
+
+public class PreparedPutContentValuesTest {
+
+    @Test
+    public void putContentValuesBlocking() {
+        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForOneContentValues();
+
+        final PutResult putResult = putStub.storIOSQLite
+                .put()
+                .contentValues(putStub.contentValues.get(0))
+                .withPutResolver(putStub.putResolver)
+                .prepare()
+                .executeAsBlocking();
+
+        putStub.verifyBehaviorForOneContentValues(putResult);
+    }
+
+    @Test
+    public void putContentValuesObservable() {
+        final PutContentValuesStub putStub = PutContentValuesStub.newPutStubForOneContentValues();
+
+        final Observable<PutResult> putResultObservable = putStub.storIOSQLite
+                .put()
+                .contentValues(putStub.contentValues.get(0))
+                .withPutResolver(putStub.putResolver)
+                .prepare()
+                .createObservable();
+
+        putStub.verifyBehaviorForOneContentValues(putResultObservable);
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutObjectTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutObjectTest.java
new file mode 100644
index 0000000..c96b036
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PreparedPutObjectTest.java
@@ -0,0 +1,44 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.runner.RunWith;
+
+import rx.Observable;
+
+@RunWith(Enclosed.class)
+public class PreparedPutObjectTest {
+
+    public static class WithoutTypeMapping {
+
+        @Test
+        public void shouldPutObjectWithoutTypeMappingBlocking() {
+            final PutObjectsStub putStub = PutObjectsStub.newPutStubForOneObjectWithoutTypeMapping();
+
+            final PutResult putResult = putStub.storIOSQLite
+                    .put()
+                    .object(putStub.items.get(0))
+                    .withPutResolver(putStub.putResolver)
+                    .prepare()
+                    .executeAsBlocking();
+
+            putStub.verifyBehaviorForOneObject(putResult);
+        }
+
+        @Test
+        public void shouldPutObjectWithoutTypeMappingAsObservable() {
+            final PutObjectsStub putStub = PutObjectsStub.newPutStubForOneObjectWithoutTypeMapping();
+
+            final Observable<PutResult> putResultObservable = putStub.storIOSQLite
+                    .put()
+                    .object(putStub.items.get(0))
+                    .withPutResolver(putStub.putResolver)
+                    .prepare()
+                    .createObservable();
+
+            putStub.verifyBehaviorForOneObject(putResultObservable);
+        }
+    }
+
+
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PutContentValuesStub.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PutContentValuesStub.java
new file mode 100644
index 0000000..cea8d9c
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PutContentValuesStub.java
@@ -0,0 +1,141 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.content.ContentValues;
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.sqlite.Changes;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import rx.Observable;
+import rx.functions.Action1;
+
+import static java.util.Collections.singletonMap;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+// stub class to avoid violation of DRY in tests
+class PutContentValuesStub {
+
+    @NonNull
+    final StorIOSQLite storIOSQLite;
+
+    @NonNull
+    private final StorIOSQLite.Internal internal;
+
+    @NonNull
+    final List<ContentValues> contentValues;
+
+    @NonNull
+    final PutResolver<ContentValues> putResolver;
+
+    private final boolean useTransaction;
+
+    @SuppressWarnings("unchecked")
+    private PutContentValuesStub(boolean useTransaction, int numberOfItems) {
+        this.useTransaction = useTransaction;
+
+        storIOSQLite = mock(StorIOSQLite.class);
+        internal = mock(StorIOSQLite.Internal.class);
+
+        when(storIOSQLite.internal())
+                .thenReturn(internal);
+
+        when(storIOSQLite.put())
+                .thenReturn(new PreparedPut.Builder(storIOSQLite));
+
+        contentValues = new ArrayList<ContentValues>(numberOfItems);
+
+        for (int i = 0; i < numberOfItems; i++) {
+            contentValues.add(mock(ContentValues.class));
+        }
+
+        putResolver = (PutResolver<ContentValues>) mock(PutResolver.class);
+
+        when(putResolver.performPut(eq(storIOSQLite), any(ContentValues.class)))
+                .thenReturn(PutResult.newInsertResult(1, TestItem.TABLE));
+    }
+
+    @NonNull
+    static PutContentValuesStub newPutStubForOneContentValues() {
+        return new PutContentValuesStub(false, 1);
+    }
+
+    @NonNull
+    static PutContentValuesStub newPutStubForMultipleContentValues(boolean useTransaction) {
+        return new PutContentValuesStub(useTransaction, 3);
+    }
+
+    void verifyBehaviorForMultipleContentValues(@NonNull PutResults<ContentValues> putResults) {
+        // only one call to storIOSQLite.put() should occur
+        verify(storIOSQLite, times(1)).put();
+
+        // number of calls to putResolver's performPut() should be equal to number of objects
+        verify(putResolver, times(contentValues.size())).performPut(eq(storIOSQLite), any(ContentValues.class));
+
+        // each item should be "put"
+        for (final ContentValues cv : contentValues) {
+            verify(putResolver, times(1)).performPut(storIOSQLite, cv);
+        }
+
+        verifyTransactionBehavior();
+    }
+
+    void verifyBehaviorForMultipleContentValues(@NonNull Observable<PutResults<ContentValues>> putResultsObservable) {
+        new ObservableBehaviorChecker<PutResults<ContentValues>>()
+                .observable(putResultsObservable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<PutResults<ContentValues>>() {
+                    @Override
+                    public void call(PutResults<ContentValues> putResults) {
+                        verifyBehaviorForMultipleContentValues(putResults);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+
+    void verifyBehaviorForOneContentValues(@NonNull PutResult putResult) {
+        verifyBehaviorForMultipleContentValues(PutResults.newInstance(singletonMap(contentValues.get(0), putResult)));
+    }
+
+    void verifyBehaviorForOneContentValues(@NonNull Observable<PutResult> putResultObservable) {
+        new ObservableBehaviorChecker<PutResult>()
+                .observable(putResultObservable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<PutResult>() {
+                    @Override
+                    public void call(PutResult putResult) {
+                        verifyBehaviorForOneContentValues(putResult);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+
+    private void verifyTransactionBehavior() {
+        if (useTransaction) {
+            verify(internal, times(1)).beginTransaction();
+            verify(internal, times(1)).setTransactionSuccessful();
+            verify(internal, times(1)).endTransaction();
+
+            // if put() operation used transaction, only one notification should be thrown
+            verify(internal, times(1))
+                    .notifyAboutChanges(eq(Changes.newInstance(TestItem.TABLE)));
+        } else {
+            verify(internal, times(0)).beginTransaction();
+            verify(internal, times(0)).setTransactionSuccessful();
+            verify(internal, times(0)).endTransaction();
+
+            // if put() operation didn't use transaction,
+            // number of notifications should be equal to number of objects
+            verify(internal, times(contentValues.size()))
+                    .notifyAboutChanges(eq(Changes.newInstance(TestItem.TABLE)));
+        }
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PutObjectsStub.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PutObjectsStub.java
new file mode 100644
index 0000000..d96e50b
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/PutObjectsStub.java
@@ -0,0 +1,216 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.support.annotation.NonNull;
+
+import com.pushtorefresh.storio.sqlite.Changes;
+import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping;
+import com.pushtorefresh.storio.sqlite.StorIOSQLite;
+import com.pushtorefresh.storio.test.ObservableBehaviorChecker;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import rx.Observable;
+import rx.functions.Action1;
+
+import static java.util.Collections.singleton;
+import static java.util.Collections.singletonMap;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+// stub class to avoid violation of DRY in tests
+class PutObjectsStub {
+
+    @NonNull
+    final StorIOSQLite storIOSQLite;
+
+    @NonNull
+    private final StorIOSQLite.Internal internal;
+
+    @NonNull
+    final List<TestItem> items;
+
+    @NonNull
+    final PutResolver<TestItem> putResolver;
+
+    @NonNull
+    private final SQLiteTypeMapping<TestItem> typeMapping;
+
+    @NonNull
+    private final Map<TestItem, PutResult> itemsToPutResultsMap;
+
+    private final boolean withTypeMapping, useTransaction;
+
+    @SuppressWarnings("unchecked")
+    private PutObjectsStub(boolean withTypeMapping, boolean useTransaction, int numberOfItems) {
+        this.withTypeMapping = withTypeMapping;
+        this.useTransaction = useTransaction;
+
+        storIOSQLite = mock(StorIOSQLite.class);
+        internal = mock(StorIOSQLite.Internal.class);
+
+        when(storIOSQLite.internal())
+                .thenReturn(internal);
+
+        when(storIOSQLite.put())
+                .thenReturn(new PreparedPut.Builder(storIOSQLite));
+
+        items = new ArrayList<TestItem>(numberOfItems);
+        itemsToPutResultsMap = new HashMap<TestItem, PutResult>(numberOfItems);
+
+        for (int i = 0; i < numberOfItems; i++) {
+            final TestItem testItem = TestItem.newInstance();
+            items.add(testItem);
+
+            final PutResult putResult = mock(PutResult.class);
+
+            when(putResult.affectedTables()).thenReturn(singleton(TestItem.TABLE));
+
+            itemsToPutResultsMap.put(testItem, putResult);
+        }
+
+        putResolver = (PutResolver<TestItem>) mock(PutResolver.class);
+
+        when(putResolver.performPut(eq(storIOSQLite), any(TestItem.class)))
+                .thenAnswer(new Answer<PutResult>() {
+                    @SuppressWarnings("SuspiciousMethodCalls")
+                    @Override
+                    public PutResult answer(InvocationOnMock invocation) throws Throwable {
+                        return itemsToPutResultsMap.get(invocation.getArguments()[1]);
+                    }
+                });
+
+        typeMapping = mock(SQLiteTypeMapping.class);
+
+        if (withTypeMapping) {
+            when(internal.typeMapping(TestItem.class)).thenReturn(typeMapping);
+            when(typeMapping.putResolver()).thenReturn(putResolver);
+        }
+    }
+
+    @NonNull
+    static PutObjectsStub newPutStubForOneObjectWithoutTypeMapping() {
+        return new PutObjectsStub(false, false, 1);
+    }
+
+    @NonNull
+    static PutObjectsStub newPutStubForOneObjectWithTypeMapping() {
+        return new PutObjectsStub(true, false, 1);
+    }
+
+    @NonNull
+    static PutObjectsStub newPutStubForMultipleObjectsWithoutTypeMappingWithTransaction() {
+        return new PutObjectsStub(false, true, 3);
+    }
+
+    @NonNull
+    static PutObjectsStub newPutStubForMultipleObjectsWithTypeMappingWithTransaction() {
+        return new PutObjectsStub(true, true, 3);
+    }
+
+    @NonNull
+    static PutObjectsStub newPutStubForMultipleObjectsWithoutTypeMappingWithoutTransaction() {
+        return new PutObjectsStub(false, false, 3);
+    }
+
+    @NonNull
+    static PutObjectsStub newPutStubForMultipleObjectsWithTypeMappingWithoutTransaction() {
+        return new PutObjectsStub(true, false, 3);
+    }
+
+    void verifyBehaviorForMultipleObjects(@NonNull PutResults<TestItem> putResults) {
+        // should be called once because of Performance!
+        verify(storIOSQLite).internal();
+
+        // only one call to storIOSQLite.put() should occur
+        verify(storIOSQLite, times(1)).put();
+
+        // number of calls to putResolver's performPut() should be equal to number of objects
+        verify(putResolver, times(items.size())).performPut(eq(storIOSQLite), any(TestItem.class));
+
+        for (final TestItem testItem : items) {
+            // put resolver should be invoked for each item
+            verify(putResolver, times(1)).performPut(storIOSQLite, testItem);
+
+            final PutResult expectedPutResult = itemsToPutResultsMap.get(testItem);
+
+            assertEquals(expectedPutResult, putResults.results().get(testItem));
+        }
+
+        assertEquals(itemsToPutResultsMap.size(), putResults.results().size());
+
+        verifyTransactionBehavior();
+
+        if (withTypeMapping) {
+            // should be called for each item
+            verify(internal, times(items.size())).typeMapping(TestItem.class);
+
+            // should be called for each item
+            verify(typeMapping, times(items.size())).putResolver();
+        }
+
+        verifyNoMoreInteractions(storIOSQLite, internal, typeMapping, putResolver);
+    }
+
+    void verifyBehaviorForMultipleObjects(@NonNull Observable<PutResults<TestItem>> putResultsObservable) {
+        new ObservableBehaviorChecker<PutResults<TestItem>>()
+                .observable(putResultsObservable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<PutResults<TestItem>>() {
+                    @Override
+                    public void call(PutResults<TestItem> testItemPutResults) {
+                        verifyBehaviorForMultipleObjects(testItemPutResults);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+
+    void verifyBehaviorForOneObject(@NonNull PutResult putResult) {
+        verifyBehaviorForMultipleObjects(PutResults.newInstance(singletonMap(items.get(0), putResult)));
+    }
+
+    void verifyBehaviorForOneObject(@NonNull Observable<PutResult> putResultObservable) {
+        new ObservableBehaviorChecker<PutResult>()
+                .observable(putResultObservable)
+                .expectedNumberOfEmissions(1)
+                .testAction(new Action1<PutResult>() {
+                    @Override
+                    public void call(PutResult putResult) {
+                        verifyBehaviorForOneObject(putResult);
+                    }
+                })
+                .checkBehaviorOfObservable();
+    }
+
+    private void verifyTransactionBehavior() {
+        if (useTransaction) {
+            verify(internal, times(1)).beginTransaction();
+            verify(internal, times(1)).setTransactionSuccessful();
+            verify(internal, times(1)).endTransaction();
+
+            // if put() operation used transaction, only one notification should be thrown
+            verify(internal, times(1))
+                    .notifyAboutChanges(eq(Changes.newInstance(TestItem.TABLE)));
+        } else {
+            verify(internal, times(0)).beginTransaction();
+            verify(internal, times(0)).setTransactionSuccessful();
+            verify(internal, times(0)).endTransaction();
+
+            // if put() operation didn't use transaction,
+            // number of notifications should be equal to number of objects
+            verify(internal, times(items.size()))
+                    .notifyAboutChanges(eq(Changes.newInstance(TestItem.TABLE)));
+        }
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/TestItem.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/TestItem.java
new file mode 100644
index 0000000..256d146
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/operations/put/TestItem.java
@@ -0,0 +1,16 @@
+package com.pushtorefresh.storio.sqlite.operations.put;
+
+import android.support.annotation.NonNull;
+
+class TestItem {
+    static final String TABLE = "test_items";
+
+    private TestItem() {
+
+    }
+
+    @NonNull
+    static TestItem newInstance() {
+        return new TestItem();
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/DeleteQueryTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/DeleteQueryTest.java
new file mode 100644
index 0000000..eb39baa
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/DeleteQueryTest.java
@@ -0,0 +1,72 @@
+package com.pushtorefresh.storio.sqlite.queries;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class DeleteQueryTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void shouldNotAllowNullTable() {
+        DeleteQuery.builder()
+                .table(null)
+                .build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void shouldNotAllowEmptyTable() {
+        DeleteQuery.builder()
+                .table("")
+                .build();
+    }
+
+    @Test
+    public void whereClauseShouldNotBeNull() {
+        DeleteQuery deleteQuery = DeleteQuery.builder()
+                .table("test_table")
+                .build();
+
+        assertNotNull(deleteQuery.where());
+        assertEquals("", deleteQuery.where());
+    }
+
+    @Test
+    public void whereArgsShouldNotBeNull() {
+        DeleteQuery deleteQuery = DeleteQuery.builder()
+                .table("test_table")
+                .build();
+
+        assertNotNull(deleteQuery.whereArgs());
+        assertTrue(deleteQuery.whereArgs().isEmpty());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void shouldThrowExceptionIfWhereArgsSpecifiedWithoutWhereClause() {
+        DeleteQuery.builder()
+                .table("test_table")
+                .whereArgs("someArg") // Without WHERE clause!
+                .build();
+    }
+
+    @Test
+    public void buildWithNormalValues() {
+        final String table = "test_table";
+        final String where = "test_where";
+        final Object[] whereArgs = {"arg1", "arg2", "arg3"};
+
+        final DeleteQuery deleteQuery = DeleteQuery.builder()
+                .table(table)
+                .where(where)
+                .whereArgs(whereArgs)
+                .build();
+
+        assertEquals(table, deleteQuery.table());
+        assertEquals(where, deleteQuery.where());
+        assertEquals(Arrays.asList(whereArgs), deleteQuery.whereArgs());
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/InsertQueryTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/InsertQueryTest.java
new file mode 100644
index 0000000..8119a82
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/InsertQueryTest.java
@@ -0,0 +1,47 @@
+package com.pushtorefresh.storio.sqlite.queries;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+public class InsertQueryTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void shouldNotAllowNullTable() {
+        InsertQuery.builder()
+                .table(null)
+                .build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void shouldNotAllowEmptyTable() {
+        InsertQuery.builder()
+                .table("")
+                .build();
+    }
+
+    @Test
+    public void nullColumnHackShouldBeNullByDefault() {
+        InsertQuery insertQuery = InsertQuery.builder()
+                .table("test_table")
+                .build();
+
+        assertNull(insertQuery.nullColumnHack());
+    }
+
+    @Test
+    public void buildWithNormalValues() {
+        final String table = "test_table";
+        final String nullColumnHack = "test_null_column_hack";
+
+        final InsertQuery insertQuery = InsertQuery.builder()
+                .table(table)
+                .nullColumnHack(nullColumnHack)
+                .build();
+
+        assertEquals(table, insertQuery.table());
+        assertEquals(nullColumnHack, insertQuery.nullColumnHack());
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/QueryTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/QueryTest.java
new file mode 100644
index 0000000..ea0b0b5
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/QueryTest.java
@@ -0,0 +1,150 @@
+package com.pushtorefresh.storio.sqlite.queries;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class QueryTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void shouldNotAllowNullTable() {
+        Query.builder()
+                .table(null)
+                .build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void shouldNotAllowEmptyTable() {
+        Query.builder()
+                .table("")
+                .build();
+    }
+
+    @Test
+    public void distinctShouldBeFalseByDefault() {
+        Query query = Query.builder()
+                .table("test_table")
+                .build();
+
+        assertFalse(query.distinct());
+    }
+
+    @Test
+    public void columnsShouldNotBeNull() {
+        Query query = Query.builder()
+                .table("test_table")
+                .build();
+
+        assertNotNull(query.columns());
+        assertTrue(query.columns().isEmpty());
+    }
+
+    @Test
+    public void whereClauseShouldNotBeNull() {
+        Query query = Query.builder()
+                .table("test_table")
+                .build();
+
+        assertNotNull(query.where());
+        assertEquals("", query.where());
+    }
+
+    @Test
+    public void whereArgsShouldNotBeNull() {
+        Query query = Query.builder()
+                .table("test_table")
+                .build();
+
+        assertNotNull(query.whereArgs());
+        assertTrue(query.whereArgs().isEmpty());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void shouldThrowExceptionIfWhereArgsSpecifiedWithoutWhereClause() {
+        Query.builder()
+                .table("test_table")
+                .whereArgs("someArg") // Without WHERE clause!
+                .build();
+    }
+
+    @Test
+    public void groupByShouldNotBeNull() {
+        Query query = Query.builder()
+                .table("test_table")
+                .build();
+
+        assertNotNull(query.groupBy());
+        assertEquals("", query.groupBy());
+    }
+
+    @Test
+    public void havingShouldNotBeNull() {
+        Query query = Query.builder()
+                .table("test_table")
+                .build();
+
+        assertNotNull(query.having());
+        assertEquals("", query.having());
+    }
+
+    @Test
+    public void orderByShouldNotBeNull() {
+        Query query = Query.builder()
+                .table("test_table")
+                .build();
+
+        assertNotNull(query.orderBy());
+        assertEquals("", query.orderBy());
+    }
+
+    @Test
+    public void limitShouldNotBeNull() {
+        Query query = Query.builder()
+                .table("test_table")
+                .build();
+
+        assertNotNull(query.limit());
+        assertEquals("", query.limit());
+    }
+
+    @Test
+    public void buildWithNormalValues() {
+        final String table = "test_table";
+        final boolean distinct = true;
+        final String[] columns = {"column1", "column2", "column3"};
+        final String where = "test_where";
+        final Object[] whereArgs = {"arg1", "arg2", "arg3"};
+        final String groupBy = "test_group_by";
+        final String having = "test_having";
+        final String orderBy = "test_order_by";
+        final String limit = "test_limit";
+
+        final Query query = Query.builder()
+                .table(table)
+                .distinct(distinct)
+                .columns(columns)
+                .where(where)
+                .whereArgs(whereArgs)
+                .groupBy(groupBy)
+                .having(having)
+                .orderBy(orderBy)
+                .limit(limit)
+                .build();
+
+        assertEquals(table, query.table());
+        assertEquals(distinct, query.distinct());
+        assertEquals(Arrays.asList(columns), query.columns());
+        assertEquals(where, query.where());
+        assertEquals(Arrays.asList(whereArgs), query.whereArgs());
+        assertEquals(groupBy, query.groupBy());
+        assertEquals(having, query.having());
+        assertEquals(orderBy, query.orderBy());
+        assertEquals(limit, query.limit());
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/RawQueryTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/RawQueryTest.java
new file mode 100644
index 0000000..264724e
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/RawQueryTest.java
@@ -0,0 +1,78 @@
+package com.pushtorefresh.storio.sqlite.queries;
+
+import com.google.common.collect.HashMultiset;
+
+import org.junit.Test;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class RawQueryTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void shouldNotAllowNullQuery() {
+        RawQuery.builder()
+                .query(null)
+                .build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void shouldNotAllowEmptyQuery() {
+        RawQuery.builder()
+                .query("")
+                .build();
+    }
+
+    @Test
+    public void argsShouldNotBeNull() {
+        RawQuery rawQuery = RawQuery.builder()
+                .query("lalala I know SQL")
+                .build();
+
+        assertNotNull(rawQuery.args());
+        assertTrue(rawQuery.args().isEmpty());
+    }
+
+    @Test
+    public void observesTablesShouldNotBeNull() {
+        RawQuery rawQuery = RawQuery.builder()
+                .query("lalala I know SQL")
+                .build();
+
+        assertNotNull(rawQuery.observesTables());
+        assertTrue(rawQuery.observesTables().isEmpty());
+    }
+
+    @Test
+    public void affectsTablesShouldNotBeNull() {
+        RawQuery rawQuery = RawQuery.builder()
+                .query("lalala I know SQL")
+                .build();
+
+        assertNotNull(rawQuery.affectsTables());
+        assertTrue(rawQuery.affectsTables().isEmpty());
+    }
+
+    @Test
+    public void buildWithNormalValues() {
+        final String query = "test_query";
+        final Object[] args = {"arg1", "arg2", "arg3"};
+        final String[] observesTables = {"table_to_observe_1", "table_to_observe_2"};
+        final String[] affectsTables = {"table_to_affect_1", "table_to_affect_2"};
+
+        final RawQuery rawQuery = RawQuery.builder()
+                .query(query)
+                .args(args)
+                .observesTables(observesTables)
+                .affectsTables(affectsTables)
+                .build();
+
+        assertEquals(query, rawQuery.query());
+        assertEquals(asList(args), rawQuery.args());
+        assertEquals(HashMultiset.create(asList(observesTables)), HashMultiset.create(rawQuery.observesTables()));
+        assertEquals(HashMultiset.create(asList(affectsTables)), HashMultiset.create(rawQuery.affectsTables()));
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/UpdateQueryTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/UpdateQueryTest.java
new file mode 100644
index 0000000..0b4e92d
--- /dev/null
+++ b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/queries/UpdateQueryTest.java
@@ -0,0 +1,63 @@
+package com.pushtorefresh.storio.sqlite.queries;
+
+import org.junit.Test;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class UpdateQueryTest {
+
+    @SuppressWarnings("ConstantConditions")
+    @Test(expected = NullPointerException.class)
+    public void shouldNotAllowNullTable() {
+        UpdateQuery.builder()
+                .table(null)
+                .build();
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void shouldNotAllowEmptyTable() {
+        UpdateQuery.builder()
+                .table("")
+                .build();
+    }
+
+    @Test
+    public void whereClauseShouldNotBeNull() {
+        UpdateQuery updateQuery = UpdateQuery.builder()
+                .table("test_table")
+                .build();
+
+        assertNotNull(updateQuery.where());
+        assertEquals("", updateQuery.where());
+    }
+
+    @Test
+    public void whereArgsShouldNotBeNull() {
+        UpdateQuery updateQuery = UpdateQuery.builder()
+                .table("test_table")
+                .build();
+
+        assertNotNull(updateQuery.whereArgs());
+        assertTrue(updateQuery.whereArgs().isEmpty());
+    }
+
+    @Test
+    public void buildWithNormalValues() {
+        final String table = "test_table";
+        final String where = "test_where";
+        final Object[] whereArgs = {"arg1", "arg2", "arg3"};
+
+        final UpdateQuery updateQuery = UpdateQuery.builder()
+                .table(table)
+                .where(where)
+                .whereArgs(whereArgs)
+                .build();
+
+        assertEquals(table, updateQuery.table());
+        assertEquals(where, updateQuery.where());
+        assertEquals(asList(whereArgs), updateQuery.whereArgs());
+    }
+}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/DeleteQueryTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/DeleteQueryTest.java
deleted file mode 100644
index cc5bbcc..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/DeleteQueryTest.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package com.pushtorefresh.storio.sqlite.query;
-
-import org.junit.Test;
-
-import java.util.Arrays;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-public class DeleteQueryTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void shouldNotAllowNullTable() {
-        DeleteQuery.builder()
-                .table(null)
-                .build();
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void shouldNotAllowEmptyTable() {
-        DeleteQuery.builder()
-                .table("")
-                .build();
-    }
-
-    @Test
-    public void whereClauseShouldNotBeNull() {
-        DeleteQuery deleteQuery = DeleteQuery.builder()
-                .table("test_table")
-                .build();
-
-        assertNotNull(deleteQuery.where());
-        assertEquals("", deleteQuery.where());
-    }
-
-    @Test
-    public void whereArgsShouldNotBeNull() {
-        DeleteQuery deleteQuery = DeleteQuery.builder()
-                .table("test_table")
-                .build();
-
-        assertNotNull(deleteQuery.whereArgs());
-        assertTrue(deleteQuery.whereArgs().isEmpty());
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void shouldThrowExceptionIfWhereArgsSpecifiedWithoutWhereClause() {
-        DeleteQuery.builder()
-                .table("test_table")
-                .whereArgs("someArg") // Without WHERE clause!
-                .build();
-    }
-
-    @Test
-    public void buildWithNormalValues() {
-        final String table = "test_table";
-        final String where = "test_where";
-        final Object[] whereArgs = {"arg1", "arg2", "arg3"};
-
-        final DeleteQuery deleteQuery = DeleteQuery.builder()
-                .table(table)
-                .where(where)
-                .whereArgs(whereArgs)
-                .build();
-
-        assertEquals(table, deleteQuery.table());
-        assertEquals(where, deleteQuery.where());
-        assertEquals(Arrays.asList(whereArgs), deleteQuery.whereArgs());
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/InsertQueryTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/InsertQueryTest.java
deleted file mode 100644
index 2bb9b8b..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/InsertQueryTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.pushtorefresh.storio.sqlite.query;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
-public class InsertQueryTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void shouldNotAllowNullTable() {
-        InsertQuery.builder()
-                .table(null)
-                .build();
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void shouldNotAllowEmptyTable() {
-        InsertQuery.builder()
-                .table("")
-                .build();
-    }
-
-    @Test
-    public void nullColumnHackShouldBeNullByDefault() {
-        InsertQuery insertQuery = InsertQuery.builder()
-                .table("test_table")
-                .build();
-
-        assertNull(insertQuery.nullColumnHack());
-    }
-
-    @Test
-    public void buildWithNormalValues() {
-        final String table = "test_table";
-        final String nullColumnHack = "test_null_column_hack";
-
-        final InsertQuery insertQuery = InsertQuery.builder()
-                .table(table)
-                .nullColumnHack(nullColumnHack)
-                .build();
-
-        assertEquals(table, insertQuery.table());
-        assertEquals(nullColumnHack, insertQuery.nullColumnHack());
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/QueryTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/QueryTest.java
deleted file mode 100644
index 5211b4d..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/QueryTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package com.pushtorefresh.storio.sqlite.query;
-
-import org.junit.Test;
-
-import java.util.Arrays;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-public class QueryTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void shouldNotAllowNullTable() {
-        Query.builder()
-                .table(null)
-                .build();
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void shouldNotAllowEmptyTable() {
-        Query.builder()
-                .table("")
-                .build();
-    }
-
-    @Test
-    public void distinctShouldBeFalseByDefault() {
-        Query query = Query.builder()
-                .table("test_table")
-                .build();
-
-        assertFalse(query.distinct());
-    }
-
-    @Test
-    public void columnsShouldNotBeNull() {
-        Query query = Query.builder()
-                .table("test_table")
-                .build();
-
-        assertNotNull(query.columns());
-        assertTrue(query.columns().isEmpty());
-    }
-
-    @Test
-    public void whereClauseShouldNotBeNull() {
-        Query query = Query.builder()
-                .table("test_table")
-                .build();
-
-        assertNotNull(query.where());
-        assertEquals("", query.where());
-    }
-
-    @Test
-    public void whereArgsShouldNotBeNull() {
-        Query query = Query.builder()
-                .table("test_table")
-                .build();
-
-        assertNotNull(query.whereArgs());
-        assertTrue(query.whereArgs().isEmpty());
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void shouldThrowExceptionIfWhereArgsSpecifiedWithoutWhereClause() {
-        Query.builder()
-                .table("test_table")
-                .whereArgs("someArg") // Without WHERE clause!
-                .build();
-    }
-
-    @Test
-    public void groupByShouldNotBeNull() {
-        Query query = Query.builder()
-                .table("test_table")
-                .build();
-
-        assertNotNull(query.groupBy());
-        assertEquals("", query.groupBy());
-    }
-
-    @Test
-    public void havingShouldNotBeNull() {
-        Query query = Query.builder()
-                .table("test_table")
-                .build();
-
-        assertNotNull(query.having());
-        assertEquals("", query.having());
-    }
-
-    @Test
-    public void orderByShouldNotBeNull() {
-        Query query = Query.builder()
-                .table("test_table")
-                .build();
-
-        assertNotNull(query.orderBy());
-        assertEquals("", query.orderBy());
-    }
-
-    @Test
-    public void limitShouldNotBeNull() {
-        Query query = Query.builder()
-                .table("test_table")
-                .build();
-
-        assertNotNull(query.limit());
-        assertEquals("", query.limit());
-    }
-
-    @Test
-    public void buildWithNormalValues() {
-        final String table = "test_table";
-        final boolean distinct = true;
-        final String[] columns = {"column1", "column2", "column3"};
-        final String where = "test_where";
-        final Object[] whereArgs = {"arg1", "arg2", "arg3"};
-        final String groupBy = "test_group_by";
-        final String having = "test_having";
-        final String orderBy = "test_order_by";
-        final String limit = "test_limit";
-
-        final Query query = Query.builder()
-                .table(table)
-                .distinct(distinct)
-                .columns(columns)
-                .where(where)
-                .whereArgs(whereArgs)
-                .groupBy(groupBy)
-                .having(having)
-                .orderBy(orderBy)
-                .limit(limit)
-                .build();
-
-        assertEquals(table, query.table());
-        assertEquals(distinct, query.distinct());
-        assertEquals(Arrays.asList(columns), query.columns());
-        assertEquals(where, query.where());
-        assertEquals(Arrays.asList(whereArgs), query.whereArgs());
-        assertEquals(groupBy, query.groupBy());
-        assertEquals(having, query.having());
-        assertEquals(orderBy, query.orderBy());
-        assertEquals(limit, query.limit());
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/RawQueryTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/RawQueryTest.java
deleted file mode 100644
index 0bf4153..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/RawQueryTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package com.pushtorefresh.storio.sqlite.query;
-
-import com.google.common.collect.HashMultiset;
-
-import org.junit.Test;
-
-import static java.util.Arrays.asList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-public class RawQueryTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void shouldNotAllowNullQuery() {
-        RawQuery.builder()
-                .query(null)
-                .build();
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void shouldNotAllowEmptyQuery() {
-        RawQuery.builder()
-                .query("")
-                .build();
-    }
-
-    @Test
-    public void argsShouldNotBeNull() {
-        RawQuery rawQuery = RawQuery.builder()
-                .query("lalala I know SQL")
-                .build();
-
-        assertNotNull(rawQuery.args());
-        assertTrue(rawQuery.args().isEmpty());
-    }
-
-    @Test
-    public void observesTablesShouldNotBeNull() {
-        RawQuery rawQuery = RawQuery.builder()
-                .query("lalala I know SQL")
-                .build();
-
-        assertNotNull(rawQuery.observesTables());
-        assertTrue(rawQuery.observesTables().isEmpty());
-    }
-
-    @Test
-    public void affectsTablesShouldNotBeNull() {
-        RawQuery rawQuery = RawQuery.builder()
-                .query("lalala I know SQL")
-                .build();
-
-        assertNotNull(rawQuery.affectsTables());
-        assertTrue(rawQuery.affectsTables().isEmpty());
-    }
-
-    @Test
-    public void buildWithNormalValues() {
-        final String query = "test_query";
-        final Object[] args = {"arg1", "arg2", "arg3"};
-        final String[] observesTables = {"table_to_observe_1", "table_to_observe_2"};
-        final String[] affectsTables = {"table_to_affect_1", "table_to_affect_2"};
-
-        final RawQuery rawQuery = RawQuery.builder()
-                .query(query)
-                .args(args)
-                .observesTables(observesTables)
-                .affectsTables(affectsTables)
-                .build();
-
-        assertEquals(query, rawQuery.query());
-        assertEquals(asList(args), rawQuery.args());
-        assertEquals(HashMultiset.create(asList(observesTables)), HashMultiset.create(rawQuery.observesTables()));
-        assertEquals(HashMultiset.create(asList(affectsTables)), HashMultiset.create(rawQuery.affectsTables()));
-    }
-}
diff --git a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/UpdateQueryTest.java b/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/UpdateQueryTest.java
deleted file mode 100644
index 8d771eb..0000000
--- a/storio-sqlite/src/test/java/com/pushtorefresh/storio/sqlite/query/UpdateQueryTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.pushtorefresh.storio.sqlite.query;
-
-import org.junit.Test;
-
-import static java.util.Arrays.asList;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-public class UpdateQueryTest {
-
-    @SuppressWarnings("ConstantConditions")
-    @Test(expected = NullPointerException.class)
-    public void shouldNotAllowNullTable() {
-        UpdateQuery.builder()
-                .table(null)
-                .build();
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void shouldNotAllowEmptyTable() {
-        UpdateQuery.builder()
-                .table("")
-                .build();
-    }
-
-    @Test
-    public void whereClauseShouldNotBeNull() {
-        UpdateQuery updateQuery = UpdateQuery.builder()
-                .table("test_table")
-                .build();
-
-        assertNotNull(updateQuery.where());
-        assertEquals("", updateQuery.where());
-    }
-
-    @Test
-    public void whereArgsShouldNotBeNull() {
-        UpdateQuery updateQuery = UpdateQuery.builder()
-                .table("test_table")
-                .build();
-
-        assertNotNull(updateQuery.whereArgs());
-        assertTrue(updateQuery.whereArgs().isEmpty());
-    }
-
-    @Test
-    public void buildWithNormalValues() {
-        final String table = "test_table";
-        final String where = "test_where";
-        final Object[] whereArgs = {"arg1", "arg2", "arg3"};
-
-        final UpdateQuery updateQuery = UpdateQuery.builder()
-                .table(table)
-                .where(where)
-                .whereArgs(whereArgs)
-                .build();
-
-        assertEquals(table, updateQuery.table());
-        assertEquals(where, updateQuery.where());
-        assertEquals(asList(whereArgs), updateQuery.whereArgs());
-    }
-}
diff --git a/storio-test-without-rxjava/src/test/java/com/pushtorefresh/storio/test_without_rxjava/contentresolver/DefaultStorIOContentResolverTest.java b/storio-test-without-rxjava/src/test/java/com/pushtorefresh/storio/test_without_rxjava/contentresolver/DefaultStorIOContentResolverTest.java
index c848d92..7885427 100644
--- a/storio-test-without-rxjava/src/test/java/com/pushtorefresh/storio/test_without_rxjava/contentresolver/DefaultStorIOContentResolverTest.java
+++ b/storio-test-without-rxjava/src/test/java/com/pushtorefresh/storio/test_without_rxjava/contentresolver/DefaultStorIOContentResolverTest.java
@@ -5,11 +5,11 @@
 import android.net.Uri;
 
 import com.pushtorefresh.storio.contentresolver.impl.DefaultStorIOContentResolver;
-import com.pushtorefresh.storio.contentresolver.operation.delete.DeleteResolver;
-import com.pushtorefresh.storio.contentresolver.operation.get.GetResolver;
-import com.pushtorefresh.storio.contentresolver.operation.put.PutResolver;
-import com.pushtorefresh.storio.contentresolver.query.DeleteQuery;
-import com.pushtorefresh.storio.contentresolver.query.Query;
+import com.pushtorefresh.storio.contentresolver.operations.delete.DeleteResolver;
+import com.pushtorefresh.storio.contentresolver.operations.get.GetResolver;
+import com.pushtorefresh.storio.contentresolver.operations.put.PutResolver;
+import com.pushtorefresh.storio.contentresolver.queries.DeleteQuery;
+import com.pushtorefresh.storio.contentresolver.queries.Query;
 
 import org.junit.Test;
 
diff --git a/storio-test-without-rxjava/src/test/java/com/pushtorefresh/storio/test_without_rxjava/sqlite/DefaultStorIOSQLiteTest.java b/storio-test-without-rxjava/src/test/java/com/pushtorefresh/storio/test_without_rxjava/sqlite/DefaultStorIOSQLiteTest.java
index 39790ee..01c545f 100644
--- a/storio-test-without-rxjava/src/test/java/com/pushtorefresh/storio/test_without_rxjava/sqlite/DefaultStorIOSQLiteTest.java
+++ b/storio-test-without-rxjava/src/test/java/com/pushtorefresh/storio/test_without_rxjava/sqlite/DefaultStorIOSQLiteTest.java
@@ -4,9 +4,9 @@
 import android.database.sqlite.SQLiteOpenHelper;
 
 import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite;
-import com.pushtorefresh.storio.sqlite.operation.get.GetResolver;
-import com.pushtorefresh.storio.sqlite.operation.put.PutResolver;
-import com.pushtorefresh.storio.sqlite.query.Query;
+import com.pushtorefresh.storio.sqlite.operations.get.GetResolver;
+import com.pushtorefresh.storio.sqlite.operations.put.PutResolver;
+import com.pushtorefresh.storio.sqlite.queries.Query;
 
 import org.junit.Test;
 
