|
2 | 2 |
|
3 | 3 | namespace Blueprint;
|
4 | 4 |
|
5 |
| -use Doctrine\DBAL\Types\Type; |
6 | 5 | use Illuminate\Database\Eloquent\Model;
|
7 | 6 | use Illuminate\Filesystem\Filesystem;
|
| 7 | +use Illuminate\Support\Str; |
8 | 8 |
|
9 | 9 | class Tracer
|
10 | 10 | {
|
@@ -61,7 +61,7 @@ private function appClasses($paths): array
|
61 | 61 |
|
62 | 62 | return array_filter(array_map(function (\SplFIleInfo $file) {
|
63 | 63 | if ($file->getExtension() !== 'php') {
|
64 |
| - return; |
| 64 | + return []; |
65 | 65 | }
|
66 | 66 |
|
67 | 67 | $content = $this->filesystem->get($file->getPathName());
|
@@ -92,126 +92,113 @@ private function loadModel(string $class)
|
92 | 92 |
|
93 | 93 | private function extractColumns(Model $model): array
|
94 | 94 | {
|
95 |
| - $table = $model->getConnection()->getTablePrefix() . $model->getTable(); |
96 |
| - $schema = $model->getConnection()->getDoctrineSchemaManager(); |
97 |
| - |
98 |
| - if (!Type::hasType('enum')) { |
99 |
| - Type::addType('enum', EnumType::class); |
100 |
| - $databasePlatform = $schema->getDatabasePlatform(); |
101 |
| - $databasePlatform->registerDoctrineTypeMapping('enum', 'enum'); |
102 |
| - } |
103 |
| - |
104 |
| - $database = null; |
105 |
| - if (strpos($table, '.')) { |
106 |
| - [$database, $table] = explode('.', $table); |
107 |
| - } |
108 |
| - |
109 |
| - $columns = $schema->listTableColumns($table, $database); |
110 |
| - |
111 |
| - $uses_enums = collect($columns)->contains(fn ($column) => $column->getType() instanceof \Blueprint\EnumType); |
112 |
| - |
113 |
| - if ($uses_enums) { |
114 |
| - $definitions = $model->getConnection()->getDoctrineConnection()->fetchAllAssociative($schema->getDatabasePlatform()->getListTableColumnsSQL($table, $database)); |
115 |
| - |
116 |
| - collect($columns)->filter(fn ($column) => $column->getType() instanceof \Blueprint\EnumType)->each(function ($column, $key) use ($definitions) { |
117 |
| - $definition = collect($definitions)->where('Field', $key)->first(); |
118 |
| - |
119 |
| - $column->options = \Blueprint\EnumType::extractOptions($definition['Type']); |
120 |
| - }); |
121 |
| - } |
122 |
| - |
123 |
| - return $columns; |
| 95 | + return $model->getConnection()->getSchemaBuilder()->getColumns($model->getTable()); |
124 | 96 | }
|
125 | 97 |
|
126 |
| - /** |
127 |
| - * @param \Doctrine\DBAL\Schema\Column[] $columns |
128 |
| - */ |
129 | 98 | private function mapColumns(array $columns): array
|
130 | 99 | {
|
131 | 100 | return collect($columns)
|
132 |
| - ->map([self::class, 'columns']) |
| 101 | + ->keyBy('name') |
| 102 | + ->map([self::class, 'columnAttributes']) |
133 | 103 | ->toArray();
|
134 | 104 | }
|
135 | 105 |
|
136 |
| - public static function columns(\Doctrine\DBAL\Schema\Column $column, string $key): string |
| 106 | + public static function columnAttributes(array $column): string |
137 | 107 | {
|
138 | 108 | $attributes = [];
|
139 | 109 |
|
140 |
| - $type = self::translations($column->getType()->getName()); |
| 110 | + $type = self::translations($column); |
141 | 111 |
|
142 |
| - if (in_array($type, ['decimal', 'float'])) { |
143 |
| - if ($column->getPrecision()) { |
144 |
| - $type .= ':' . $column->getPrecision(); |
| 112 | + if (in_array($type, ['decimal', 'float', 'time', 'timetz', 'datetime', 'datetimetz', 'timestamp', 'timestamptz', 'geography', 'geometry']) |
| 113 | + && str_contains($column['type'], '(')) { |
| 114 | + $options = Str::between($column['type'], '(', ')'); |
| 115 | + if ($options) { |
| 116 | + $type .= ':' . $options; |
145 | 117 | }
|
146 |
| - if ($column->getScale()) { |
147 |
| - $type .= ',' . $column->getScale(); |
| 118 | + } elseif (in_array($type, ['string', 'char']) && str_contains($column['type'], '(')) { |
| 119 | + $length = Str::between($column['type'], '(', ')'); |
| 120 | + if ($length != 255) { |
| 121 | + $type .= ':' . $length; |
148 | 122 | }
|
149 |
| - } elseif ($type === 'string' && $column->getLength()) { |
150 |
| - if ($column->getLength() !== 255) { |
151 |
| - $type .= ':' . $column->getLength(); |
152 |
| - } |
153 |
| - } elseif ($type === 'text') { |
154 |
| - if ($column->getLength() > 65535) { |
155 |
| - $type = 'longtext'; |
156 |
| - } |
157 |
| - } elseif ($type === 'enum' && !empty($column->options)) { |
158 |
| - $type .= ':' . implode(',', $column->options); |
| 123 | + } elseif (in_array($type, ['enum', 'set'])) { |
| 124 | + $options = Str::between($column['type'], '(', ')'); |
| 125 | + $type .= ':' . $options; |
159 | 126 | }
|
160 | 127 |
|
161 | 128 | // TODO: guid/uuid
|
162 | 129 |
|
163 | 130 | $attributes[] = $type;
|
164 | 131 |
|
165 |
| - if ($column->getUnsigned()) { |
| 132 | + if (str_contains($column['type'], 'unsigned')) { |
166 | 133 | $attributes[] = 'unsigned';
|
167 | 134 | }
|
168 | 135 |
|
169 |
| - if (!$column->getNotnull()) { |
| 136 | + if ($column['nullable']) { |
170 | 137 | $attributes[] = 'nullable';
|
171 | 138 | }
|
172 | 139 |
|
173 |
| - if ($column->getAutoincrement()) { |
| 140 | + if ($column['auto_increment']) { |
174 | 141 | $attributes[] = 'autoincrement';
|
175 | 142 | }
|
176 | 143 |
|
177 |
| - if (!is_null($column->getDefault())) { |
178 |
| - $attributes[] = 'default:' . $column->getDefault(); |
| 144 | + if ($column['default']) { |
| 145 | + $attributes[] = 'default:' . $column['default']; |
179 | 146 | }
|
180 | 147 |
|
181 | 148 | return implode(' ', $attributes);
|
182 | 149 | }
|
183 | 150 |
|
184 |
| - private static function translations(string $type): string |
| 151 | + private static function translations(array $column): string |
185 | 152 | {
|
186 |
| - static $mappings = [ |
187 |
| - 'array' => 'string', |
188 |
| - 'bigint' => 'biginteger', |
189 |
| - 'binary' => 'binary', |
190 |
| - 'blob' => 'binary', |
191 |
| - 'boolean' => 'boolean', |
| 153 | + $type = match ($column['type']) { |
| 154 | + 'tinyint(1)', 'bit' => 'boolean', |
| 155 | + 'nvarchar(max)' => 'text', |
| 156 | + default => null, |
| 157 | + }; |
| 158 | + |
| 159 | + $type ??= match ($column['type_name']) { |
| 160 | + 'bigint', 'int8' => 'biginteger', |
| 161 | + 'binary', 'varbinary', 'bytea', 'image', 'blob', 'tinyblob', 'mediumblob', 'longblob' => 'binary', |
| 162 | + // 'bit', 'varbit' => 'bit', |
| 163 | + 'boolean', 'bool' => 'boolean', |
| 164 | + 'char', 'bpchar', 'nchar' => 'char', |
192 | 165 | 'date' => 'date',
|
193 |
| - 'date_immutable' => 'date', |
194 |
| - 'dateinterval' => 'date', |
195 |
| - 'datetime' => 'datetime', |
196 |
| - 'datetime_immutable' => 'datetime', |
197 |
| - 'datetimetz' => 'datetimetz', |
198 |
| - 'datetimetz_immutable' => 'datetimetz', |
199 |
| - 'decimal' => 'decimal', |
| 166 | + 'datetime', 'datetime2' => 'datetime', |
| 167 | + 'datetimeoffset' => 'datetimetz', |
| 168 | + 'decimal', 'numeric' => 'decimal', |
| 169 | + 'double', 'float8' => 'double', |
200 | 170 | 'enum' => 'enum',
|
201 |
| - 'float' => 'float', |
202 |
| - 'guid' => 'string', |
203 |
| - 'integer' => 'integer', |
| 171 | + 'float', 'real', 'float4' => 'float', |
| 172 | + 'geography' => 'geography', |
| 173 | + 'geometry', 'geometrycollection', 'linestring', 'multilinestring', 'multipoint', 'multipolygon', 'point', 'polygon' => 'geometry', |
| 174 | + // 'box', 'circle', 'line', 'lseg', 'path' => 'geometry', |
| 175 | + 'integer', 'int', 'int4' => 'integer', |
| 176 | + 'inet', 'cidr' => 'ipaddress', |
| 177 | + // 'interval' => 'interval', |
204 | 178 | 'json' => 'json',
|
205 |
| - 'object' => 'string', |
206 |
| - 'simple_array' => 'string', |
207 |
| - 'smallint' => 'smallinteger', |
208 |
| - 'string' => 'string', |
209 |
| - 'text' => 'text', |
| 179 | + 'jsonb' => 'jsonb', |
| 180 | + 'longtext' => 'longtext', |
| 181 | + 'macaddr', 'macaddr8' => 'macadress', |
| 182 | + 'mediumint' => 'mediuminteger', |
| 183 | + 'mediumtext' => 'mediumtext', |
| 184 | + // 'money', 'smallmoney' => 'money', |
| 185 | + 'set' => 'set', |
| 186 | + 'smallint', 'int2' => 'smallinteger', |
| 187 | + 'text', 'ntext' => 'text', |
210 | 188 | 'time' => 'time',
|
211 |
| - 'time_immutable' => 'time', |
212 |
| - ]; |
213 |
| - |
214 |
| - return $mappings[$type] ?? 'string'; |
| 189 | + 'timestamp' => 'timestamp', |
| 190 | + 'timestamptz' => 'timestamptz', |
| 191 | + 'timetz' => 'timetz', |
| 192 | + 'tinyint' => 'tinyinteger', |
| 193 | + 'tinytext' => 'tinytext', |
| 194 | + 'uuid', 'uniqueidentifier' => 'uuid', |
| 195 | + 'varchar', 'nvarchar' => 'string', |
| 196 | + // 'xml' => 'xml', |
| 197 | + 'year' => 'year', |
| 198 | + default => null, |
| 199 | + }; |
| 200 | + |
| 201 | + return $type ?? 'string'; |
215 | 202 | }
|
216 | 203 |
|
217 | 204 | private function translateColumns(array $columns): array
|
|
0 commit comments