Lines 90.90% 10 / 11
Functions and Methods 75.00% 3 / 4
Classes and Traits 0.00% 0 / 1
Name Lines Functions and Methods CRAP Classes and Traits
MySqlGrammar 90.90% 10 / 11 75.00% 3 / 4 9.06 0.00% 0 / 1
 wrap 100.00% 1 / 1 100.00% 1 / 1 1
 compileEmptyInsert 100.00% 1 / 1 100.00% 1 / 1 1
 compileOffset 80.00% 4 / 5 0.00% 0 / 1 3.07
 compileLock 100.00% 4 / 4 100.00% 1 / 1 4
1<?php
2
3declare(strict_types=1);
4
5namespace BlueprintAU\Radiant\Database\Grammars;
6
7use BlueprintAU\Radiant\Database\Query\Enums\LockType;
8use BlueprintAU\Radiant\Database\Query\QueryBuilder;
9
10/**
11 * The MySQL dialect of the SQL Grammar.
12 *
13 * Identifiers are quoted with backticks (embedded backticks doubled). Plain
14 * `INSERT ... RETURNING` is not supported, so {@see usesReturning()} stays
15 * false and `insertGetId()` falls back to `lastInsertId()` via
16 * {@see compileInsertForId()}'s `returnsKey` flag. Row locks render as
17 * `for update` and `lock in share mode`; an offset without a limit is padded
18 * with the unsigned-bigint maximum so the offset is accepted.
19 */
20final class MySqlGrammar extends Grammar
21{
22    /**
23     * Wrap an identifier in MySQL backticks.
24     *
25     * @param  string  $value
26     * @return string
27     */
28    protected function wrap(string $value): string
29    {
30        return '`' . str_replace('`', '``', $value) . '`';
31    }
32
33    /**
34     * Compile the empty-row insert — the one-row `VALUES ()` fallback.
35     *
36     * MySQL has no `INSERT ... DEFAULT VALUES` form; it accepts the one-row
37     * `VALUES ()` and applies the column defaults.
38     *
39     * @param  QueryBuilder  $builder
40     * @return string
41     */
42    #[\Override]
43    protected function compileEmptyInsert(QueryBuilder $builder): string
44    {
45        return "INSERT INTO {$this->wrapFromTable($builder)} () VALUES ()";
46    }
47
48    /**
49     * Compile the offset clause, padding a bare offset with the max limit.
50     *
51     * @param  QueryBuilder  $builder
52     * @return string
53     */
54    protected function compileOffset(QueryBuilder $builder): string
55    {
56        if ($builder->getOffset() === null) {
57            return '';
58        }
59        if ($builder->getLimit() === null) {
60            return 'LIMIT 18446744073709551615 OFFSET ' . $builder->getOffset();
61        }
62        return 'OFFSET ' . $builder->getOffset();
63    }
64
65    /**
66     * Compile the row lock for MySQL.
67     *
68     * @param  QueryBuilder  $builder
69     * @return string
70     */
71    protected function compileLock(QueryBuilder $builder): string
72    {
73        return match ($builder->getLock()) {
74            null => '',
75            LockType::Update => 'FOR UPDATE',
76            LockType::Shared => 'LOCK IN SHARE MODE',
77        };
78    }
79}