Completed
Branch feature/pre-split (cccde6)
by Anton
03:54
created

SQLServerTable::save()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 4
nop 3
dl 0
loc 17
rs 8.8571
c 0
b 0
f 0
1
<?php
2
/**
3
 * Spiral Framework, Core Components
4
 *
5
 * @author    Wolfy-J
6
 */
7
namespace Spiral\Database\Drivers\SQLServer\Schemas;
8
9
use Psr\Log\LoggerInterface;
10
use Spiral\Database\Entities\AbstractHandler as Behaviour;
11
use Spiral\Database\Schemas\Prototypes\AbstractColumn;
12
use Spiral\Database\Schemas\Prototypes\AbstractIndex;
13
use Spiral\Database\Schemas\Prototypes\AbstractReference;
14
use Spiral\Database\Schemas\Prototypes\AbstractTable;
15
16
class SQLServerTable extends AbstractTable
17
{
18
    /**
19
     * {@inheritdoc}
20
     *
21
     * SQLServer will reload schemas after successful savw.
22
     */
23
    public function save(
24
        int $behaviour = Behaviour::DO_ALL,
25
        LoggerInterface $logger = null,
26
        bool $reset = true
27
    ) {
28
        parent::save($behaviour, $logger, $reset);
29
30
        if ($reset) {
31
            foreach ($this->fetchColumns() as $column) {
32
                $currentColumn = $this->current->findColumn($column->getName());
33
                if (!empty($currentColumn) && $column->compare($currentColumn)) {
34
                    //SQLServer is going to add some automatic constrains, let's handle them
35
                    $this->current->registerColumn($column);
36
                }
37
            }
38
        }
39
    }
40
41
    /**
42
     * {@inheritdoc}
43
     */
44
    protected function fetchColumns(): array
45
    {
46
        $query = 'SELECT * FROM [information_schema].[columns] INNER JOIN [sys].[columns] AS [sysColumns] '
47
            . 'ON (object_name([object_id]) = [table_name] AND [sysColumns].[name] = [COLUMN_NAME]) '
48
            . 'WHERE [table_name] = ?';
49
50
        $result = [];
51
        foreach ($this->driver->query($query, [$this->getName()]) as $schema) {
52
            //Column initialization needs driver to properly resolve enum type
53
            $result[] = SQLServerColumn::createInstance(
54
                $this->getName(),
55
                $schema,
56
                $this->driver
57
            );
58
        }
59
60
        return $result;
61
    }
62
63
    /**
64
     * {@inheritdoc}
65
     */
66
    protected function fetchIndexes(): array
67
    {
68
        $query = 'SELECT [indexes].[name] AS [indexName], [cl].[name] AS [columnName], '
69
            . "[is_primary_key] AS [isPrimary], [is_unique] AS [isUnique]\n"
70
            . "FROM [sys].[indexes] AS [indexes]\n"
71
            . "INNER JOIN [sys].[index_columns] as [columns]\n"
72
            . "  ON [indexes].[object_id] = [columns].[object_id] AND [indexes].[index_id] = [columns].[index_id]\n"
73
            . "INNER JOIN [sys].[columns] AS [cl]\n"
74
            . "  ON [columns].[object_id] = [cl].[object_id] AND [columns].[column_id] = [cl].[column_id]\n"
75
            . "INNER JOIN [sys].[tables] AS [t]\n"
76
            . "  ON [indexes].[object_id] = [t].[object_id]\n"
77
            . 'WHERE [t].[name] = ? AND [is_primary_key] = 0 ORDER BY [indexes].[name], [indexes].[index_id], [columns].[index_column_id]';
78
79
        $result = $indexes = [];
80
        foreach ($this->driver->query($query, [$this->getName()]) as $index) {
81
            //Collecting schemas first
82
            $indexes[$index['indexName']][] = $index;
83
        }
84
85
        foreach ($indexes as $name => $schema) {
86
            //Once all columns are aggregated we can finally create an index
87
            $result[] = SQLServerIndex::createInstance($this->getName(), $schema);
88
        }
89
90
        return $result;
91
    }
92
93
    /**
94
     * {@inheritdoc}
95
     */
96
    protected function fetchReferences(): array
97
    {
98
        $references = $this->driver->query('sp_fkeys @fktable_name = ?', [$this->getName()]);
99
100
        $result = [];
101
        foreach ($references as $schema) {
102
            $result[] = SQlServerReference::createInstance(
103
                $this->getName(),
104
                $this->getPrefix(),
105
                $schema
106
            );
107
        }
108
109
        return $result;
110
    }
111
112
    /**
113
     * {@inheritdoc}
114
     */
115
    protected function fetchPrimaryKeys(): array
116
    {
117
        $query = "SELECT [indexes].[name] AS [indexName], [cl].[name] AS [columnName]\n"
118
            . "FROM [sys].[indexes] AS [indexes]\n"
119
            . "INNER JOIN [sys].[index_columns] as [columns]\n"
120
            . "  ON [indexes].[object_id] = [columns].[object_id] AND [indexes].[index_id] = [columns].[index_id]\n"
121
            . "INNER JOIN [sys].[columns] AS [cl]\n"
122
            . "  ON [columns].[object_id] = [cl].[object_id] AND [columns].[column_id] = [cl].[column_id]\n"
123
            . "INNER JOIN [sys].[tables] AS [t]\n"
124
            . "  ON [indexes].[object_id] = [t].[object_id]\n"
125
            . 'WHERE [t].[name] = ? AND [is_primary_key] = 1 ORDER BY [indexes].[name], [indexes].[index_id], [columns].[index_column_id]';
126
127
        $result = [];
128
        foreach ($this->driver->query($query, [$this->getName()]) as $schema) {
129
            $result[] = $schema['columnName'];
130
        }
131
132
        return $result;
133
    }
134
135
    /**
136
     * {@inheritdoc}
137
     */
138
    protected function createColumn(string $name): AbstractColumn
139
    {
140
        return new SQLServerColumn($this->getName(), $name, $this->driver->getTimezone());
141
    }
142
143
    /**
144
     * {@inheritdoc}
145
     */
146
    protected function createIndex(string $name): AbstractIndex
147
    {
148
        return new SQLServerIndex($this->getName(), $name);
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     */
154
    protected function createForeign(string $name): AbstractReference
155
    {
156
        return new SQlServerReference($this->getName(), $this->getPrefix(), $name);
157
    }
158
}