Passed
Push — master ( a1316c...a86692 )
by belamov
03:53
created

PostgresGrammarWithRangeTypes::typeTstzrange()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Belamov\PostgresRange;
4
5
use Illuminate\Database\Schema\Blueprint;
6
use Illuminate\Database\Schema\Grammars\PostgresGrammar;
7
use Illuminate\Support\Facades\DB;
8
use Illuminate\Support\Fluent;
9
10
class PostgresGrammarWithRangeTypes extends PostgresGrammar
11
{
12
    /**
13
     * @return string
14
     */
15
    public function typeDaterange(): string
16
    {
17
        return 'daterange';
18
    }
19
20
    /**
21
     * @return string
22
     */
23
    public function typeTsrange(): string
24
    {
25
        return 'tsrange';
26
    }
27
28
    /**
29
     * @return string
30
     */
31
    public function typeTstzrange(): string
32
    {
33
        return 'tstzrange';
34
    }
35
36
    /**
37
     * @return string
38
     */
39
    public function typeNumrange(): string
40
    {
41
        return 'numrange';
42
    }
43
44
    /**
45
     * @return string
46
     */
47
    public function typeInt4range(): string
48
    {
49
        return 'int4range';
50
    }
51
52
    /**
53
     * @return string
54
     */
55
    public function typeInt8range(): string
56
    {
57
        return 'int8range';
58
    }
59
60
    /**
61
     * @return string
62
     */
63
    public function typeTimeRange(): string
64
    {
65
        $this->addTimeRangeType();
66
67
        return config('postgres-range.timerange_typename');
68
    }
69
70
    protected function addTimeRangeType(): void
71
    {
72
        $timeDiffFunctionName = config('postgres-range.timerange_subtype_diff_function_name');
73
        $timeRangeTypeName = config('postgres-range.timerange_typename');
74
75
        DB::statement(
76
            "CREATE OR REPLACE FUNCTION {$timeDiffFunctionName}(x time, y time) RETURNS float8 AS
77
        'SELECT EXTRACT(EPOCH FROM (x - y))' LANGUAGE sql STRICT IMMUTABLE;"
78
        );
79
80
        DB::statement("DO $$
81
        BEGIN
82
            IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = '{$timeRangeTypeName}') THEN
83
                CREATE TYPE {$timeRangeTypeName} AS RANGE (
84
                    subtype = time,
85
                    subtype_diff = {$timeDiffFunctionName}
86
                );
87
            END IF;
88
        END$$;"
89
        );
90
    }
91
92
    public function getFluentCommands(): array
93
    {
94
        return array_merge(parent::getFluentCommands(), ['excludeRangeOverlapping']);
95
    }
96
97
    /**
98
     * @param  Blueprint  $blueprint
99
     * @param  Fluent  $command
100
     * @return string
101
     */
102
    public function compileExcludeRangeOverlapping(Blueprint $blueprint, Fluent $command): string
103
    {
104
        if (! empty($command->additionalColumns)) {
105
            $this->addBtreeGistExtension();
106
        }
107
108
        return sprintf('alter table %s add exclude using gist (%s %s with &&)',
109
            $this->wrapTable($blueprint),
110
            $this->getAdditionalColumnsForExclude($command->additionalColumns),
111
            $this->wrap($command->column)
112
        );
113
    }
114
115
    protected function addBtreeGistExtension(): void
116
    {
117
        DB::statement('CREATE EXTENSION IF NOT EXISTS btree_gist;');
118
    }
119
120
    /**
121
     * @param  array|null  $additionalColumns
122
     * @return string
123
     */
124
    private function getAdditionalColumnsForExclude(?array $additionalColumns): string
125
    {
126
        $columns = '';
127
128
        foreach ($additionalColumns as $additionalColumn) {
129
            $columns .= "{$additionalColumn} WITH =,";
130
        }
131
132
        return $columns;
133
    }
134
}
135