Completed
Push — master ( f5e696...7c0e7c )
by Rasmus
03:36
created

ProjectionQuery   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 204
Duplicated Lines 0 %

Coupling/Cohesion

Components 4
Dependencies 2

Test Coverage

Coverage 73.91%

Importance

Changes 0
Metric Value
wmc 20
lcom 4
cbo 2
dl 0
loc 204
ccs 34
cts 46
cp 0.7391
rs 10
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A where() 0 8 2
A order() 0 6 1
A innerJoin() 0 4 1
A limit() 0 15 3
A page() 0 12 3
A join() 0 8 1
A buildNodes() 0 4 1
A buildConditions() 0 4 1
A buildOrderTerms() 0 4 1
A leftJoin() 0 4 1
A rightJoin() 0 4 1
A buildLimit() 0 6 3
1
<?php
2
3
namespace mindplay\sql\model\query;
4
5
use InvalidArgumentException;
6
use mindplay\sql\model\Driver;
7
use mindplay\sql\model\schema\Table;
8
use mindplay\sql\model\TypeProvider;
9
10
/**
11
 * Abstract base class for Query types involving projections, e.g. `INSERT`, `SELECT` or `UPDATE`.
12
 *
13
 * By "projection", we mean a projection of certain tables, possibly `JOIN`s, conditions, order
14
 * and limit, all of which affect the scope and order of the set of data the query operates on.
15
 */
16
abstract class ProjectionQuery extends Query
17
{
18
    /**
19
     * @var Driver
20
     */
21
    protected $driver;
22
23
    /**
24
     * @var Table root Table of this query (from which JOIN clauses may extend the projection)
25
     */
26
    protected $root;
27
28
    /**
29
     * @var string[] list of JOIN clauses extending from the root Table of this query
30
     */
31
    protected $joins = [];
32
33
    /**
34
     * @var string[] list of condition expressions to apply to the WHERE clause
35
     */
36
    protected $conditions = [];
37
38
    /**
39
     * @var string[] list of ORDER BY terms
40
     */
41
    protected $order = [];
42
43
    /**
44
     * @var int|null
45
     */
46
    protected $offset;
47
48
    /**
49
     * @var int|null
50
     */
51
    protected $limit;
52
53
    /**
54
     * @param Table        $root
55
     * @param Driver       $driver
56
     * @param TypeProvider $types
57
     */
58 1
    public function __construct(Table $root, Driver $driver, TypeProvider $types)
59
    {
60 1
        parent::__construct($types);
61
62 1
        $this->driver = $driver;
63 1
        $this->root = $root;
64 1
    }
65
66
    /**
67
     * @param string|string[] $exprs one or more condition expressions to apply to the WHERE clause
68
     *
69
     * @return $this
70
     */
71 1
    public function where($exprs)
72
    {
73 1
        foreach ((array) $exprs as $expr) {
74 1
            $this->conditions[] = $expr;
75
        }
76
77 1
        return $this;
78
    }
79
80
    /**
81
     * @param string $expr order-by expression (which may include a trailing "ASC" or "DESC" modifier)
82
     * 
83
     * @return $this
84
     */
85 1
    public function order($expr)
86
    {
87 1
        $this->order[] = "{$expr}";
88
        
89 1
        return $this;
90
    }
91
    
92
    /**
93
     * @param Table  $table
94
     * @param string $expr join condition
95
     *
96
     * @return $this
97
     */
98 1
    public function innerJoin(Table $table, $expr)
99
    {
100 1
        return $this->join("INNER", $table, $expr);
101
    }
102
103
    /**
104
     * @param Table  $table
105
     * @param string $expr join condition
106
     *
107
     * @return $this
108
     */
109
    public function leftJoin(Table $table, $expr)
110
    {
111
        return $this->join("LEFT", $table, $expr);
112
    }
113
114
    /**
115
     * @param Table  $table
116
     * @param string $expr join condition
117
     *
118
     * @return $this
119
     */
120
    public function rightJoin(Table $table, $expr)
121
    {
122
        return $this->join("RIGHT", $table, $expr);
123
    }
124
125
    /**
126
     * @param int      $limit  max. number of records
127
     * @param int|null $offset base-0 record number offset
128
     *
129
     * @return $this
130
     *
131
     * @throws InvalidArgumentException if the given limit is less than 1, or if the given offset if less than 0
132
     */
133 1
    public function limit($limit, $offset = null)
134
    {
135 1
        if ($limit < 1) {
136
            throw new InvalidArgumentException("limit out of range: {$limit}");
137
        }
138
139 1
        if ($offset < 0) {
140
            throw new InvalidArgumentException("offset out of range: {$offset}");
141
        }
142
143 1
        $this->limit = $limit;
144 1
        $this->offset = $offset;
145
146 1
        return $this;
147
    }
148
149
    /**
150
     * @param int $page_num  base-1 page number
151
     * @param int $page_size number of records per page
152
     *
153
     * @return $this
154
     *
155
     * @throws InvalidArgumentException if the given page number or page size are less than 1
156
     */
157 1
    public function page($page_num, $page_size)
158
    {
159 1
        if ($page_size < 1) {
160
            throw new InvalidArgumentException("page size out of range: {$page_size}");
161
        }
162
163 1
        if ($page_num < 1) {
164
            throw new InvalidArgumentException("page number out of range: {$page_num}");
165
        }
166
167 1
        return $this->limit($page_size, ($page_num - 1) * $page_size);
168
    }
169
170
    /**
171
     * @param string $type join type ("INNER", "LEFT", etc.)
172
     * @param Table  $table
173
     * @param string $expr join condition
174
     *
175
     * @return $this
176
     */
177 1
    protected function join($type, Table $table, $expr)
178
    {
179 1
        $table_expr = $table->getNode();
180
181 1
        $this->joins[] = "{$type} JOIN {$table_expr} ON {$expr}";
182
183 1
        return $this;
184
    }
185
186
    /**
187
     * @return string root table expression and JOIN clauses (for use in the FROM clause of an SQL statement)
188
     */
189 1
    protected function buildNodes()
190
    {
191 1
        return implode("\n", array_merge([$this->root->getNode()], $this->joins));
192
    }
193
194
    /**
195
     * @return string combined condition expression (for use in the WHERE clause of an SQL statement)
196
     */
197 1
    protected function buildConditions()
198
    {
199 1
        return implode(" AND ", $this->conditions);
200
    }
201
    
202
    /**
203
     * @return string order terms (for use in the ORDER BY clause of an SQL statement)
204
     */
205 1
    protected function buildOrderTerms()
206
    {
207 1
        return implode(', ', $this->order);
208
    }
209
210
    /**
211
     * @return string the LIMIT/OFFSET clause (or an empty string, if no limit has been set)
212
     */
213
    protected function buildLimit()
214
    {
215
        return $this->limit !== null
216
            ? "\nLIMIT {$this->limit}" . ($this->offset !== null ? " OFFSET {$this->offset}" : '')
217
            : ''; // no limit or offset
218
    }
219
}
220