diff --git a/src/Storm/Model/Loader.php b/src/Storm/Model/Loader.php
index ead8016d25774d4a78aa94fee64fe492e569cfe9..61352097fee9c0e6202bdff8fdb6848fda6671d6 100644
--- a/src/Storm/Model/Loader.php
+++ b/src/Storm/Model/Loader.php
@@ -397,6 +397,9 @@ class Storm_Model_Loader {
    *
    */
   public function findAllBy($args) {
+    if ($args instanceof Storm_Query)
+      return $this->getPersistenceStrategy()->findAllBy($args);
+
     $filter_given_func = isset($args['callback']) ? $args['callback'] : null;
 
     $filter_func = null;
@@ -452,25 +455,38 @@ class Storm_Model_Loader {
   }
 
 
-
   /**
    * @param array $args
    * @return Storm_Model_Abstract
    */
   public function findFirstBy($args) {
-    $args['limit'] = 1;
-    $instances = $this->findAllBy($args);
+    $instances = $this->findAllBy($this->_prepareFirstBy($args));
 
-    if (count($instances) == 0) {
+    if (count($instances) == 0)
       return null;
-    }
+
     $first_instance = reset($instances);
     $this->cacheInstance($first_instance);
     return $first_instance;
   }
 
 
+  protected function _prepareFirstBy($args) {
+    if ($args instanceof Storm_Query)
+      return $args->limit(1);
+
+    $args['limit'] = 1;
+    return $args;
+  }
+
+
   public function fetchAllBy($fields, $params) {
     return $this->getPersistenceStrategy()->fetchAllBy($fields, $params);
   }
+
+
+  public function greater(string $key,
+                          string $value) : Storm_Model_PersistenceStrategy_Clause {
+    return Storm_Model_PersistenceStrategy_Clause::greater($key, $value);
+  }
 }
diff --git a/src/Storm/Model/PersistenceStrategy/Clause.php b/src/Storm/Model/PersistenceStrategy/Clause.php
index a1c6025eb80253716197bb7caf12815a8cc4ced0..b41320c55089c9e1989c3daf3f1e55531f562dce 100644
--- a/src/Storm/Model/PersistenceStrategy/Clause.php
+++ b/src/Storm/Model/PersistenceStrategy/Clause.php
@@ -48,6 +48,7 @@ class Storm_Model_PersistenceStrategy_Clause {
     CLAUSE_LIMIT = 'limit',
     CLAUSE_LIMIT_PAGE = 'limitPage',
     CLAUSE_ORDER_BY = 'order by',
+    CLAUSE_GROUP_BY = 'group by',
     PERCENT = '%';
 
 
@@ -88,6 +89,8 @@ class Storm_Model_PersistenceStrategy_Clause {
       return (new Storm_Model_PersistenceStrategy_ClauseLimitPage($key, $operator, $value_or_array));
     if (static::CLAUSE_ORDER_BY === $operator)
       return (new Storm_Model_PersistenceStrategy_ClauseOrderBy($key, $operator, $value_or_array));
+    if (static::CLAUSE_GROUP_BY === $operator)
+      return (new Storm_Model_PersistenceStrategy_ClauseGroupBy($key, $operator, $value_or_array));
 
     return (new static($key, $operator, $value_or_array));
   }
@@ -196,6 +199,11 @@ class Storm_Model_PersistenceStrategy_Clause {
   }
 
 
+  public static function group(string $value) : self {
+    return static::newFor(static::CLAUSE_GROUP_BY, static::CLAUSE_GROUP_BY, $value);
+  }
+
+
   public static function order(string $key, ?Storm_Model_PersistenceStrategy_Clause $clause = null) : self {
     return static::newFor($key, static::CLAUSE_ORDER_BY, $clause);
   }
@@ -548,6 +556,28 @@ class Storm_Model_PersistenceStrategy_ClauseLimitPage
 
 
 
+class Storm_Model_PersistenceStrategy_ClauseGroupBy
+  extends Storm_Model_PersistenceStrategy_Clause {
+
+  public function assemble($select) : self {
+    $select->group($this->getValueOrArray());
+    return $this;
+  }
+
+
+  public function getFormatDb($table) : string {
+    return '';
+  }
+
+
+  public function containAttibuteInVolatile(array $model) : bool {
+    return true;
+  }
+}
+
+
+
+
 class Storm_Model_PersistenceStrategy_ClauseOrderBy
   extends Storm_Model_PersistenceStrategy_Clause {
 
diff --git a/src/Storm/Model/PersistenceStrategy/Db.php b/src/Storm/Model/PersistenceStrategy/Db.php
index c5157b57bca4c9ec2d1776f004f03e223d9a730b..ed70a15d2504ea309c69cdae59f3dbc6941d9c23 100644
--- a/src/Storm/Model/PersistenceStrategy/Db.php
+++ b/src/Storm/Model/PersistenceStrategy/Db.php
@@ -172,7 +172,7 @@ class Storm_Model_PersistenceStrategy_Db
    */
   public function _generateSelectFor($args) {
     if ($args instanceof Storm_Query)
-      return $args->assembleFor($this->getTable()->select());
+      return $args->getSelectAndAssemble();
 
     if (array_key_exists('role', $args) && array_key_exists('model', $args)) {
       $model = $args['model'];
diff --git a/src/Storm/Model/PersistenceStrategy/Volatile.php b/src/Storm/Model/PersistenceStrategy/Volatile.php
index 7abb84075309d1a1d085dacfb1250aa6bd9f05fc..afdd2b73c2120ae55b109503a5d421fbb427718c 100644
--- a/src/Storm/Model/PersistenceStrategy/Volatile.php
+++ b/src/Storm/Model/PersistenceStrategy/Volatile.php
@@ -24,13 +24,14 @@ THE SOFTWARE.
 
 */
 
-class Storm_Model_PersistenceStrategy_Volatile  extends Storm_Model_PersistenceStrategy_Abstract {
+class Storm_Model_PersistenceStrategy_Volatile
+  extends Storm_Model_PersistenceStrategy_Abstract {
+
   protected
     $_instances = [],
     $desc_order = false,
     $_table;
 
-
   public function getTable() {
     return $this->_table;
   }
@@ -52,7 +53,7 @@ class Storm_Model_PersistenceStrategy_Volatile  extends Storm_Model_PersistenceS
     $limit = $filtered->getLimit();
     $limit_page = $filtered->getLimitPage();
 
-    $page_size=0;
+    $page_size = 0;
     if ($limit_page) {
       list($page, $page_size) = $limit_page;
       if ($page > 0) $page -= 1;
diff --git a/src/Storm/Model/PersistenceStrategy/Volatile/Filtered.php b/src/Storm/Model/PersistenceStrategy/Volatile/Filtered.php
index 0baff2c0cd71bd064e26e17740b47bf47dcc0f3b..2f0da257a0ebf2e9a116cff4da9d4d43c5a095fc 100644
--- a/src/Storm/Model/PersistenceStrategy/Volatile/Filtered.php
+++ b/src/Storm/Model/PersistenceStrategy/Volatile/Filtered.php
@@ -47,11 +47,12 @@ class Storm_Model_PersistenceStrategy_Volatile_Filtered {
   }
 
 
-  public function extractRoleAndModel(Storm_Model_Loader $loader) : self {
+  public function extractRoleAndModel(Storm_Model_Loader $loader) {
     if ($this->_query)
       return $this;
 
-    if (array_key_exists('role', $this->_select) && array_key_exists('model', $this->_select)) {
+    if (array_key_exists('role', $this->_select)
+        && array_key_exists('model', $this->_select)) {
       $model = $this->_select['model'];
       $role = $this->_select['role'];
       unset($this->_select['model']);
@@ -65,7 +66,8 @@ class Storm_Model_PersistenceStrategy_Volatile_Filtered {
     }
 
     if (array_key_exists('scope', $this->_select)) {
-      $this->_select = array_merge($this->_select, array_change_key_case($this->_select['scope']));
+      $this->_select = array_merge($this->_select,
+                                   array_change_key_case($this->_select['scope']));
       unset($this->_select['scope']);
     }
 
@@ -111,8 +113,8 @@ class Storm_Model_PersistenceStrategy_Volatile_Filtered {
 
 
   public function getGroupBy() : string {
-    if (!$this->_select)
-      return '';
+    if ($this->_query)
+      return $this->_query->getGroupByValue();
 
     $group_by = $this->_select['group_by'] ?? '';
     unset($this->_select['group_by']);
diff --git a/src/Storm/Query.php b/src/Storm/Query.php
index c116a582e1ce2720365fbdc1591774a26d310baa..207e2110c0b32a7f8d15f77c1c5773cb228f9f26 100644
--- a/src/Storm/Query.php
+++ b/src/Storm/Query.php
@@ -33,6 +33,7 @@ class Storm_Query {
   protected Storm_Model_Loader $_loader;
   protected ?Storm_Model_PersistenceStrategy_Clause $_clause_limit;
   protected ?Storm_Model_PersistenceStrategy_Clause $_clause_limit_page;
+  protected ?Storm_Model_PersistenceStrategy_Clause $_clause_group_by;
 
   public function __construct() {
     $this->_clauses = [];
@@ -40,6 +41,7 @@ class Storm_Query {
     $this->_terms = [];
     $this->_clause_limit = null;
     $this->_clause_limit_page = null;
+    $this->_clause_group_by = null;
   }
 
 
@@ -61,7 +63,9 @@ class Storm_Query {
   }
 
 
-  public function assembleFor($select) {
+  public function getSelectAndAssemble() {
+    $select = $this->_loader->getTable()->select();
+
     foreach ($this->getClauses() as $clause)
       $clause->assemble($select);
 
@@ -74,6 +78,9 @@ class Storm_Query {
     if ($this->_clause_limit_page)
       $this->_clause_limit_page->assemble($select);
 
+    if ($this->_clause_group_by)
+      $this->_clause_group_by->assemble($select);
+
     return $select;
   }
 
@@ -100,12 +107,23 @@ class Storm_Query {
 
 
   public function getLimitValue() {
-    return $this->_clause_limit ? $this->_clause_limit->getValueOrArray() : '';
+    return $this->_clause_limit ?
+      $this->_clause_limit->getValueOrArray()
+      : '';
   }
 
 
   public function getLimitPageValue() : ?array {
-    return $this->_clause_limit_page ? $this->_clause_limit_page->getValueOrArray() : null;
+    return $this->_clause_limit_page
+      ? $this->_clause_limit_page->getValueOrArray()
+      : null;
+  }
+
+
+  public function getGroupByValue() : string {
+    return $this->_clause_group_by
+      ? $this->_clause_group_by->getValueOrArray()
+      : '';
   }
 
 
@@ -121,6 +139,12 @@ class Storm_Query {
   }
 
 
+  protected function _group(string $value) : self {
+    $this->_clause_group_by = Storm_Model_PersistenceStrategy_Clause::group($value);
+    return $this;
+  }
+
+
   protected function _eq(string $key, string $value) : self {
     $this->_clauses [] = Storm_Model_PersistenceStrategy_Clause::equal($key, $value);
     return $this;
@@ -287,21 +311,21 @@ class Storm_Query {
 
   protected function _fetchAll() : array {
     return $this->_loader
-      ? $this->_loader->getPersistenceStrategy()->findAllBy($this)
+      ? $this->_loader->findAllBy($this)
       : [];
   }
 
 
   protected function _count() : array {
     return $this->_loader
-      ? $this->_loader->getPersistenceStrategy()->countBy($this)
+      ? $this->_loader->countBy($this)
       : [];
   }
 
 
-  protected function _fetchFirst() : Storm_Model_Abstract {
+  protected function _fetchFirst() : ?Storm_Model_Abstract {
     return $this->_loader
-      ? $this->_loader->getPersistenceStrategy()->findFirstBy($this)
+      ? $this->_loader->findFirstBy($this)
       : null;
   }
 }
diff --git a/tests/Storm/Test/LoaderTest.php b/tests/Storm/Test/LoaderTest.php
index d30618935d4a0dcf4d1768d747ddd92e2ea6e647..f3b68db384ee10bfa498066ee560b3b60060395c 100644
--- a/tests/Storm/Test/LoaderTest.php
+++ b/tests/Storm/Test/LoaderTest.php
@@ -729,3 +729,33 @@ class Storm_Test_LoaderQueryOrderTest extends Storm_Test_LoaderTestCase {
                         $this->_select->getAttributesForLastCallOn('order'));
   }
 }
+
+
+
+
+class Storm_Test_LoaderQueryGroupByTest extends Storm_Test_LoaderTestCase {
+
+  protected $_select;
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->_table
+      ->whenCalled('select')->answers($this->_select = $this->mock())
+      ->whenCalled('fetchAll')->with($this->_select)
+      ->answers(new Zend_Db_Table_Rowset([]));
+
+    $this->_select->whenCalled('group')->answers($this->_select);
+  }
+
+
+  /** @test */
+  public function withGroupByLoaderShouldCallGroupOnDbSelect() {
+    Storm_Query::group('name')
+      ->from($this->_loader)
+      ->fetchAll();
+
+    $this->assertEquals(['name'],
+                        $this->_select->getAttributesForLastCallOn('group'));
+  }
+}
diff --git a/tests/Storm/Test/LoaderVolatileTest.php b/tests/Storm/Test/LoaderVolatileTest.php
index 09c2aa8f46d9cb52ed25a8338328303e6793f048..4dcd13c1a05b1e710f0a212a219befc02477f06e 100644
--- a/tests/Storm/Test/LoaderVolatileTest.php
+++ b/tests/Storm/Test/LoaderVolatileTest.php
@@ -1155,4 +1155,15 @@ class Storm_Test_LoaderVolatileClauseOrderTest extends Storm_Test_ModelTestCase
                         ->collect('login')
                         ->getArrayCopy());
   }
+
+
+  /** @test */
+  public function selectUsersGroupByOrder3ShouldAnswersUserAdminAndUserInvite() {
+    $this->assertEquals([0 => 'user_admin', 2 => 'user_invite'],
+                        (new Storm_Model_Collection(Storm_Query::from(Storm_Test_VolatileUser::getLoader())
+                                                    ->group('order3')
+                                                    ->fetchAll()))
+                        ->collect('login')
+                        ->getArrayCopy());
+  }
 }