PageRenderTime 52ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/Query/Grammars/PostgresGrammar.php

https://gitlab.com/biggercode/database
PHP | 304 lines | 132 code | 46 blank | 126 comment | 10 complexity | 3319729bfbfc72669b60d05bf20025b3 MD5 | raw file
  1. <?php
  2. namespace Illuminate\Database\Query\Grammars;
  3. use Illuminate\Support\Str;
  4. use Illuminate\Database\Query\Builder;
  5. class PostgresGrammar extends Grammar
  6. {
  7. /**
  8. * All of the available clause operators.
  9. *
  10. * @var array
  11. */
  12. protected $operators = [
  13. '=', '<', '>', '<=', '>=', '<>', '!=',
  14. 'like', 'not like', 'between', 'ilike',
  15. '&', '|', '#', '<<', '>>',
  16. '@>', '<@', '?', '?|', '?&', '||', '-', '-', '#-',
  17. ];
  18. /**
  19. * Compile the lock into SQL.
  20. *
  21. * @param \Illuminate\Database\Query\Builder $query
  22. * @param bool|string $value
  23. * @return string
  24. */
  25. protected function compileLock(Builder $query, $value)
  26. {
  27. if (is_string($value)) {
  28. return $value;
  29. }
  30. return $value ? 'for update' : 'for share';
  31. }
  32. /**
  33. * Compile a "where date" clause.
  34. *
  35. * @param \Illuminate\Database\Query\Builder $query
  36. * @param array $where
  37. * @return string
  38. */
  39. protected function whereDate(Builder $query, $where)
  40. {
  41. $value = $this->parameter($where['value']);
  42. return $this->wrap($where['column']).'::date '.$where['operator'].' '.$value;
  43. }
  44. /**
  45. * Compile a "where day" clause.
  46. *
  47. * @param \Illuminate\Database\Query\Builder $query
  48. * @param array $where
  49. * @return string
  50. */
  51. protected function whereDay(Builder $query, $where)
  52. {
  53. return $this->dateBasedWhere('day', $query, $where);
  54. }
  55. /**
  56. * Compile a "where month" clause.
  57. *
  58. * @param \Illuminate\Database\Query\Builder $query
  59. * @param array $where
  60. * @return string
  61. */
  62. protected function whereMonth(Builder $query, $where)
  63. {
  64. return $this->dateBasedWhere('month', $query, $where);
  65. }
  66. /**
  67. * Compile a "where year" clause.
  68. *
  69. * @param \Illuminate\Database\Query\Builder $query
  70. * @param array $where
  71. * @return string
  72. */
  73. protected function whereYear(Builder $query, $where)
  74. {
  75. return $this->dateBasedWhere('year', $query, $where);
  76. }
  77. /**
  78. * Compile a date based where clause.
  79. *
  80. * @param string $type
  81. * @param \Illuminate\Database\Query\Builder $query
  82. * @param array $where
  83. * @return string
  84. */
  85. protected function dateBasedWhere($type, Builder $query, $where)
  86. {
  87. $value = $this->parameter($where['value']);
  88. return 'extract('.$type.' from '.$this->wrap($where['column']).') '.$where['operator'].' '.$value;
  89. }
  90. /**
  91. * Compile an update statement into SQL.
  92. *
  93. * @param \Illuminate\Database\Query\Builder $query
  94. * @param array $values
  95. * @return string
  96. */
  97. public function compileUpdate(Builder $query, $values)
  98. {
  99. $table = $this->wrapTable($query->from);
  100. // Each one of the columns in the update statements needs to be wrapped in the
  101. // keyword identifiers, also a place-holder needs to be created for each of
  102. // the values in the list of bindings so we can make the sets statements.
  103. $columns = $this->compileUpdateColumns($values);
  104. $from = $this->compileUpdateFrom($query);
  105. $where = $this->compileUpdateWheres($query);
  106. return trim("update {$table} set {$columns}{$from} $where");
  107. }
  108. /**
  109. * Compile the columns for the update statement.
  110. *
  111. * @param array $values
  112. * @return string
  113. */
  114. protected function compileUpdateColumns($values)
  115. {
  116. $columns = [];
  117. // When gathering the columns for an update statement, we'll wrap each of the
  118. // columns and convert it to a parameter value. Then we will concatenate a
  119. // list of the columns that can be added into this update query clauses.
  120. foreach ($values as $key => $value) {
  121. $columns[] = $this->wrap($key).' = '.$this->parameter($value);
  122. }
  123. return implode(', ', $columns);
  124. }
  125. /**
  126. * Compile the "from" clause for an update with a join.
  127. *
  128. * @param \Illuminate\Database\Query\Builder $query
  129. * @return string|null
  130. */
  131. protected function compileUpdateFrom(Builder $query)
  132. {
  133. if (! isset($query->joins)) {
  134. return '';
  135. }
  136. $froms = [];
  137. // When using Postgres, updates with joins list the joined tables in the from
  138. // clause, which is different than other systems like MySQL. Here, we will
  139. // compile out the tables that are joined and add them to a from clause.
  140. foreach ($query->joins as $join) {
  141. $froms[] = $this->wrapTable($join->table);
  142. }
  143. if (count($froms) > 0) {
  144. return ' from '.implode(', ', $froms);
  145. }
  146. }
  147. /**
  148. * Compile the additional where clauses for updates with joins.
  149. *
  150. * @param \Illuminate\Database\Query\Builder $query
  151. * @return string
  152. */
  153. protected function compileUpdateWheres(Builder $query)
  154. {
  155. $baseWhere = $this->compileWheres($query);
  156. if (! isset($query->joins)) {
  157. return $baseWhere;
  158. }
  159. // Once we compile the join constraints, we will either use them as the where
  160. // clause or append them to the existing base where clauses. If we need to
  161. // strip the leading boolean we will do so when using as the only where.
  162. $joinWhere = $this->compileUpdateJoinWheres($query);
  163. if (trim($baseWhere) == '') {
  164. return 'where '.$this->removeLeadingBoolean($joinWhere);
  165. }
  166. return $baseWhere.' '.$joinWhere;
  167. }
  168. /**
  169. * Compile the "join" clauses for an update.
  170. *
  171. * @param \Illuminate\Database\Query\Builder $query
  172. * @return string
  173. */
  174. protected function compileUpdateJoinWheres(Builder $query)
  175. {
  176. $joinWheres = [];
  177. // Here we will just loop through all of the join constraints and compile them
  178. // all out then implode them. This should give us "where" like syntax after
  179. // everything has been built and then we will join it to the real wheres.
  180. foreach ($query->joins as $join) {
  181. foreach ($join->wheres as $where) {
  182. $method = "where{$where['type']}";
  183. $joinWheres[] = $where['boolean'].' '.$this->$method($query, $where);
  184. }
  185. }
  186. return implode(' ', $joinWheres);
  187. }
  188. /**
  189. * Compile an insert and get ID statement into SQL.
  190. *
  191. * @param \Illuminate\Database\Query\Builder $query
  192. * @param array $values
  193. * @param string $sequence
  194. * @return string
  195. */
  196. public function compileInsertGetId(Builder $query, $values, $sequence)
  197. {
  198. if (is_null($sequence)) {
  199. $sequence = 'id';
  200. }
  201. return $this->compileInsert($query, $values).' returning '.$this->wrap($sequence);
  202. }
  203. /**
  204. * Compile a truncate table statement into SQL.
  205. *
  206. * @param \Illuminate\Database\Query\Builder $query
  207. * @return array
  208. */
  209. public function compileTruncate(Builder $query)
  210. {
  211. return ['truncate '.$this->wrapTable($query->from).' restart identity' => []];
  212. }
  213. /**
  214. * Wrap a single string in keyword identifiers.
  215. *
  216. * @param string $value
  217. * @return string
  218. */
  219. protected function wrapValue($value)
  220. {
  221. if ($value === '*') {
  222. return $value;
  223. }
  224. if (Str::contains($value, '->')) {
  225. return $this->wrapJsonSelector($value);
  226. }
  227. return '"'.str_replace('"', '""', $value).'"';
  228. }
  229. /**
  230. * Wrap the given JSON selector.
  231. *
  232. * @param string $value
  233. * @return string
  234. */
  235. protected function wrapJsonSelector($value)
  236. {
  237. $path = explode('->', $value);
  238. $field = $this->wrapValue(array_shift($path));
  239. $wrappedPath = $this->wrapJsonPathAttributes($path);
  240. $attribute = array_pop($wrappedPath);
  241. if (! empty($wrappedPath)) {
  242. return $field.'->'.implode('->', $wrappedPath).'->>'.$attribute;
  243. }
  244. return $field.'->>'.$attribute;
  245. }
  246. /**
  247. * Wrap the attributes of the give JSON path.
  248. *
  249. * @param array $path
  250. * @return array
  251. */
  252. protected function wrapJsonPathAttributes($path)
  253. {
  254. return array_map(function ($attribute) {
  255. return "'$attribute'";
  256. }, $path);
  257. }
  258. }