Completed
Pull Request — master (#23)
by Damian
08:37
created

SQLite3QueryBuilder::buildLimitFragment()   D

Complexity

Conditions 10
Paths 7

Size

Total Lines 34
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 34
rs 4.8196
cc 10
eloc 18
nc 7
nop 2

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace SilverStripe\SQLite;
4
5
use SilverStripe\ORM\Queries\SQLAssignmentRow;
6
use SilverStripe\ORM\Queries\SQLInsert;
7
use SilverStripe\ORM\Queries\SQLSelect;
8
use SilverStripe\ORM\Connect\DBQueryBuilder;
9
use InvalidArgumentException;
10
11
/**
12
 * Builds a SQL query string from a SQLExpression object
13
 *
14
 * @package SQLite3
15
 */
16
class SQLite3QueryBuilder extends DBQueryBuilder
17
{
18
19
    /**
20
     * @param SQLInsert $query
21
     * @param array $parameters
22
     * @return string
23
     */
24
    protected function buildInsertQuery(SQLInsert $query, array &$parameters)
25
    {
26
        // Multi-row insert requires SQLite specific syntax prior to 3.7.11
27
        // For backwards compatibility reasons include the "union all select" syntax
28
29
        $nl = $this->getSeparator();
30
        $into = $query->getInto();
31
32
        // Column identifiers
33
        $columns = $query->getColumns();
34
35
        // Build all rows
36
        $rowParts = array();
37
        foreach ($query->getRows() as $row) {
38
            // Build all columns in this row
39
            /** @var SQLAssignmentRow $row */
40
            $assignments = $row->getAssignments();
41
            // Join SET components together, considering parameters
42
            $parts = array();
43
            foreach ($columns as $column) {
44
                // Check if this column has a value for this row
45
                if (isset($assignments[$column])) {
46
                    // Assigment is a single item array, expand with a loop here
47
                    foreach ($assignments[$column] as $assignmentSQL => $assignmentParameters) {
48
                        $parts[] = $assignmentSQL;
49
                        $parameters = array_merge($parameters, $assignmentParameters);
50
                        break;
51
                    }
52
                } else {
53
                    // This row is missing a value for a column used by another row
54
                    $parts[] = '?';
55
                    $parameters[] = null;
56
                }
57
            }
58
            $rowParts[] = implode(', ', $parts);
59
        }
60
        $columnSQL = implode(', ', $columns);
61
        $sql = "INSERT INTO {$into}{$nl}($columnSQL){$nl}SELECT " . implode("{$nl}UNION ALL SELECT ", $rowParts);
62
63
        return $sql;
64
    }
65
66
    /**
67
     * Return the LIMIT clause ready for inserting into a query.
68
     *
69
     * @param SQLSelect $query The expression object to build from
70
     * @param array $parameters Out parameter for the resulting query parameters
71
     * @return string The finalised limit SQL fragment
72
     */
73
    public function buildLimitFragment(SQLSelect $query, array &$parameters)
74
    {
75
        $nl = $this->getSeparator();
76
77
        // Ensure limit is given
78
        $limit = $query->getLimit();
79
        if (empty($limit)) {
80
            return '';
81
        }
82
83
        // For literal values return this as the limit SQL
84
        if (! is_array($limit)) {
85
            return "{$nl}LIMIT $limit";
86
        }
87
88
        // Assert that the array version provides the 'limit' key
89
        if (! array_key_exists('limit', $limit) || ($limit['limit'] !== null && ! is_numeric($limit['limit']))) {
90
            throw new InvalidArgumentException(
91
                'SQLite3QueryBuilder::buildLimitSQL(): Wrong format for $limit: '. var_export($limit, true)
92
            );
93
        }
94
95
        $clause = "{$nl}";
96
        if ($limit['limit'] !== null) {
97
            $clause .= "LIMIT {$limit['limit']} ";
98
        } else {
99
            $clause .= "LIMIT -1 ";
100
        }
101
102
        if (isset($limit['start']) && is_numeric($limit['start']) && $limit['start'] !== 0) {
103
            $clause .= "OFFSET {$limit['start']}";
104
        }
105
        return $clause;
106
    }
107
}
108