Completed
Push — master ( 391062...ff47c5 )
by Rasmus
02:37
created

InsertQuery   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 123
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 86.96%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 123
wmc 12
lcom 1
cbo 4
ccs 40
cts 46
cp 0.8696
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 3
A add() 0 18 3
B getSQL() 0 55 6
1
<?php
2
3
namespace mindplay\sql\model;
4
5
use mindplay\sql\framework\Driver;
6
use mindplay\sql\framework\TypeProvider;
7
use RuntimeException;
8
9
/**
10
 * This class represents an INSERT query.
11
 */
12
class InsertQuery extends Query
13
{
14
    /**
15
     * @var Driver
16
     */
17
    private $driver;
18
19
    /**
20
     * @var Table
21
     */
22
    private $table;
23
24
    /**
25
     * @var mixed[][] list of record maps, where Column name => value
26
     */
27
    private $records = [];
28
29
    /**
30
     * @param Driver                 $driver
31
     * @param TypeProvider           $types
32
     * @param Table                  $table  Table to INSERT into
33
     * @param mixed[]|mixed[][]|null $record optional record map (or list of record maps) where Column name => value
34
     */
35 1
    public function __construct(Driver $driver, TypeProvider $types, Table $table, array $record = null)
36
    {
37 1
        parent::__construct($types);
38
39 1
        if ($table->getAlias()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $table->getAlias() of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
40
            throw new RuntimeException("can't insert into a Table instance with an alias");
41
        }
42
43 1
        $this->driver = $driver;
44
45 1
        $this->table = $table;
46
47 1
        if ($record !== null) {
48 1
            $this->add($record);
49
        }
50 1
    }
51
52
    /**
53
     * Add one or more records to this INSERT query.
54
     *
55
     * @param mixed[]|mixed[][] $record record map (or list of record maps) where Column name => value
56
     */
57 1
    public function add(array $record)
58
    {
59 1
        reset($record);
60
61 1
        $first_key = key($record);
62
63 1
        if ($first_key === null) {
64
            return; // empty array given - no records added
65
        }
66
67 1
        if (is_array($record[$first_key])) {
68
            // append given list of records:
69 1
            $this->records = array_merge($this->records, $record);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($this->records, $record) of type array is incompatible with the declared type array<integer,array<integer,*>> of property $records.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
70
        } else {
71
            // append given single record:
72 1
            $this->records[] = $record;
73
        }
74 1
    }
75
76
    /**
77
     * @inheritdoc
78
     */
79 1
    public function getSQL()
80
    {
81 1
        if (count($this->records) === 0) {
82
            throw new RuntimeException("no records added to this query");
83
        }
84
85 1
        $table = "{$this->table}";
86
87
        /** @var Column[] $columns */
88
89 1
        $columns = array_filter(
90 1
            $this->table->listColumns(),
91
            function (Column $column) {
92 1
                return $column->isAuto() === false;
93 1
            }
94
        );
95
96 1
        $quoted_column_names = implode(
97 1
            ", ",
98
            array_map(
99 1
                function (Column $column) {
100 1
                    return $this->driver->quoteName($column->getName());
101 1
                },
102
                $columns
103
            )
104
        );
105
106 1
        $tuples = [];
107
108 1
        foreach ($this->records as $tuple_num => $record) {
109 1
            $placeholders = [];
110
111 1
            foreach ($columns as $col_index => $column) {
112 1
                $name = $column->getName();
113
                
114 1
                if (array_key_exists($name, $record)) {
115 1
                    $value = $record[$name];
116
                } elseif ($column->isRequired() === false) {
117
                    $value = $column->getDefault();
118
                } else {
119
                    throw new RuntimeException("required value '{$name}' missing from tuple # {$tuple_num}");
120
                }
121
                
122 1
                $placeholder = "c{$tuple_num}_{$col_index}";
123
                
124 1
                $placeholders[] = ":{$placeholder}";
125
                
126 1
                $this->bind($placeholder, $value, $column->getType());
127
            }
128
129 1
            $tuples[] = "(" . implode(", ", $placeholders) . ")";
130
        }
131
132 1
        return "INSERT INTO {$table} ({$quoted_column_names}) VALUES\n" . implode(",\n", $tuples);
133
    }
134
}
135