protected function processQuery(Query $query, $context): Query
    {
        $queryProperties = [];

        // Table
        $queryProperties['table'] = $this->processTable($query->table, $context);

        // Select
        foreach ($query->select as $alias => $select) {
            $queryProperties['select'][$alias] = $this->processSelect($select, $context);
        }

        // Insert
        foreach ($query->insert as $index => $insert) {
            $queryProperties['insert'][$index] = $this->processInsert($insert, $context);
        }

        // Update
        foreach ($query->update as $column => $update) {
            $column = $this->processColumnName($column, $context);
            $queryProperties['update'][$column] = $this->processValueOrSubQuery($update, $context);
        }

        // Join
        foreach ($query->join as $index => $join) {
            $queryProperties['join'][$index] = $this->processJoin($join, $context);
        }

        // Where
        foreach ($query->where as $index => $criterion) {
            $queryProperties['where'][$index] = $this->processCriterion($criterion, $context);
        }

        // Order
        foreach ($query->order as $index => $order) {
            $queryProperties['order'][$index] = $this->processOrder($order, $context);
        }

        // Offset
        $queryProperties['offset'] = $this->processValueOrSubQuery($query->offset, $context);

        // Limit
        $queryProperties['limit'] = $this->processValueOrSubQuery($query->limit, $context);

        // Is any property changed?
        $isChanged = false;
        foreach ($queryProperties as $property => $value) {
            if ($value !== $query->$property) {
                $isChanged = true;
                break;
            }
        }

        if ($isChanged) {
            $query = clone $query;
            foreach ($queryProperties as $property => $value) {
                $query->$property = $value;
            }
            return $query;
        } else {
            return $query;
        }
    }