Skip to content

Commit a0d0655

Browse files
Add support for generating indexes (#351)
1 parent 62edefe commit a0d0655

File tree

9 files changed

+175
-6
lines changed

9 files changed

+175
-6
lines changed

src/Builder.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ public function execute(Blueprint $blueprint, Filesystem $files, string $draft,
1313
$cache = $blueprint->parse($files->get('.blueprint'));
1414
}
1515

16-
$tokens = $blueprint->parse($files->get($draft));
16+
$contents = $files->get($draft);
17+
$using_indexes = preg_match('/^\s+indexes:\R/m', $contents) !== 1;
18+
19+
$tokens = $blueprint->parse($contents, $using_indexes);
1720
$tokens['cache'] = $cache['models'] ?? [];
1821
$registry = $blueprint->analyze($tokens);
1922

src/Generators/MigrationGenerator.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,16 @@ protected function buildDefinition(Model $model)
200200
$definition .= self::INDENT.sprintf('$table->string(\'%s\');', Str::lower($model->morphTo().'_type')).PHP_EOL;
201201
}
202202

203+
foreach ($model->indexes() as $index) {
204+
$index_definition = self::INDENT;
205+
$index_definition .= '$table->'.$index->type();
206+
if (count($index->columns()) > 1) {
207+
$index_definition .= "(['".implode("', '", $index->columns())."']);".PHP_EOL;
208+
} else {
209+
$index_definition .= "('{$index->columns()[0]}');".PHP_EOL;
210+
}
211+
$definition .= $index_definition;
212+
}
203213
if ($model->usesTimestamps()) {
204214
$definition .= self::INDENT.'$table->'.$model->timestampsDataType().'();'.PHP_EOL;
205215
}
@@ -292,7 +302,7 @@ protected function getTablePath($tableName, Carbon $timestamp, $overwrite = fals
292302
{
293303
$dir = 'database/migrations/';
294304
$name = '_create_'.$tableName.'_table.php';
295-
305+
296306
$file = $overwrite ? collect($this->files->files($dir))->first(function ($file) use ($tableName) {
297307
return str_contains($file, $tableName);
298308
}) : false;

src/Lexers/ModelLexer.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Blueprint\Contracts\Lexer;
66
use Blueprint\Models\Column;
7+
use Blueprint\Models\Index;
78
use Blueprint\Models\Model;
89
use Illuminate\Support\Str;
910

@@ -166,6 +167,13 @@ private function buildModel(string $name, array $columns)
166167
unset($columns['relationships']);
167168
}
168169

170+
if (isset($columns['indexes'])) {
171+
foreach ($columns['indexes'] as $index) {
172+
$model->addIndex(new Index(key($index), array_map('trim', explode(',', current($index)))));
173+
}
174+
unset($columns['indexes']);
175+
}
176+
169177
if (!isset($columns['id']) && $model->usesPrimaryKey()) {
170178
$column = $this->buildColumn('id', 'id');
171179
$model->addColumn($column);

src/Models/Index.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Blueprint\Models;
4+
5+
class Index
6+
{
7+
private $type;
8+
private $columns;
9+
10+
public function __construct(string $type, array $columns = [])
11+
{
12+
$this->type = $type;
13+
$this->columns = $columns;
14+
}
15+
16+
public function type()
17+
{
18+
return $this->type;
19+
}
20+
21+
public function columns()
22+
{
23+
return $this->columns;
24+
}
25+
}

src/Models/Model.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class Model
1515
private $columns = [];
1616
private $relationships = [];
1717
private $pivotTables = [];
18+
private $indexes = [];
1819

1920
/**
2021
* @param $name
@@ -159,6 +160,16 @@ public function addPivotTable(string $reference)
159160
$this->pivotTables[] = $segments;
160161
}
161162

163+
public function indexes(): array
164+
{
165+
return $this->indexes;
166+
}
167+
168+
public function addIndex(Index $index)
169+
{
170+
$this->indexes[] = $index;
171+
}
172+
162173
public function pivotTables(): array
163174
{
164175
return $this->pivotTables;

tests/Feature/Generator/MigrationGeneratorTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public function output_writes_migration_for_model_tree($definition, $path, $migr
7070
$this->files->expects('put')
7171
->with($timestamp_path, $this->fixture($migration));
7272

73-
$tokens = $this->blueprint->parse($this->fixture($definition));
73+
$tokens = $this->blueprint->parse($this->fixture($definition), $definition !== 'drafts/indexes.yaml');
7474
$tree = $this->blueprint->analyze($tokens);
7575

7676
$this->assertEquals(['created' => [$timestamp_path]], $this->subject->output($tree));
@@ -103,7 +103,7 @@ public function output_updates_migration_for_model_tree($definition, $path, $mig
103103
$this->files->expects('put')
104104
->with($yesterday_path, $this->fixture($migration));
105105

106-
$tokens = $this->blueprint->parse($this->fixture($definition));
106+
$tokens = $this->blueprint->parse($this->fixture($definition), $definition !== 'drafts/indexes.yaml');
107107
$tree = $this->blueprint->analyze($tokens);
108108

109109
$this->assertEquals(['updated' => [$yesterday_path]], $this->subject->output($tree, true));
@@ -746,6 +746,7 @@ public function modelTreeDataProvider()
746746
['drafts/soft-deletes.yaml', 'database/migrations/timestamp_create_comments_table.php', 'migrations/soft-deletes.php'],
747747
['drafts/with-timezones.yaml', 'database/migrations/timestamp_create_comments_table.php', 'migrations/with-timezones.php'],
748748
['drafts/relationships.yaml', 'database/migrations/timestamp_create_comments_table.php', 'migrations/relationships.php'],
749+
['drafts/indexes.yaml', 'database/migrations/timestamp_create_posts_table.php', 'migrations/indexes.php'],
749750
['drafts/unconventional.yaml', 'database/migrations/timestamp_create_teams_table.php', 'migrations/unconventional.php'],
750751
['drafts/optimize.yaml', 'database/migrations/timestamp_create_optimizes_table.php', 'migrations/optimize.php'],
751752
['drafts/model-key-constraints.yaml', 'database/migrations/timestamp_create_orders_table.php', 'migrations/model-key-constraints.php'],

tests/Unit/BuilderTest.php

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public function execute_builds_draft_content()
2424

2525
$blueprint = \Mockery::mock(Blueprint::class);
2626
$blueprint->expects('parse')
27-
->with($draft)
27+
->with($draft, true)
2828
->andReturn($tokens);
2929
$blueprint->expects('analyze')
3030
->with($tokens + ['cache' => []])
@@ -72,7 +72,7 @@ public function execute_uses_cache_and_remembers_models()
7272

7373
$blueprint = \Mockery::mock(Blueprint::class);
7474
$blueprint->expects('parse')
75-
->with($draft)
75+
->with($draft, true)
7676
->andReturn($tokens);
7777
$blueprint->expects('parse')
7878
->with('cached blueprint content')
@@ -108,4 +108,56 @@ public function execute_uses_cache_and_remembers_models()
108108

109109
$this->assertSame($generated, $actual);
110110
}
111+
112+
/**
113+
* @test
114+
*/
115+
public function execute_calls_builder_without_stripping_dashes_for_draft_file_with_indexes_defined()
116+
{
117+
$draft = 'models:';
118+
$draft .= PHP_EOL . ' Post:';
119+
$draft .= PHP_EOL . ' indexes:';
120+
$draft .= PHP_EOL . ' - index: author_id';
121+
$draft .= PHP_EOL . ' - index: author_id, published_at';
122+
123+
$tokens = [
124+
'models' => [1, 2, 3]
125+
];
126+
$registry = new Tree(['registry']);
127+
$only = [];
128+
$skip = [];
129+
$generated = ['created' => [1, 2], 'updated' => [3]];
130+
131+
$blueprint = \Mockery::mock(Blueprint::class);
132+
$blueprint->expects('parse')
133+
->with($draft, false)
134+
->andReturn($tokens);
135+
$blueprint->expects('analyze')
136+
->with($tokens + ['cache' => []])
137+
->andReturn($registry);
138+
$blueprint->expects('generate')
139+
->with($registry, $only, $skip, false)
140+
->andReturn($generated);
141+
$blueprint->expects('dump')
142+
->with([
143+
'created' => [1, 2],
144+
'updated' => [3],
145+
'models' => [1, 2, 3]
146+
])
147+
->andReturn('cacheable blueprint content');
148+
149+
$file = \Mockery::mock(Filesystem::class);
150+
$file->expects('get')
151+
->with('draft.yaml')
152+
->andReturn($draft);
153+
$file->expects('exists')
154+
->with('.blueprint')
155+
->andReturnFalse();
156+
$file->expects('put')
157+
->with('.blueprint', 'cacheable blueprint content');
158+
159+
$actual = (new Builder)->execute($blueprint, $file, 'draft.yaml');
160+
161+
$this->assertSame($generated, $actual);
162+
}
111163
}

tests/fixtures/drafts/indexes.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
models:
2+
Post:
3+
id: unsignedInteger
4+
title: string
5+
parent_post_id: id
6+
author_id: id
7+
published_at: timestamp nullable
8+
word_count: integer unsigned
9+
location: geometry
10+
indexes:
11+
- primary: id
12+
- index: author_id
13+
- index: author_id, published_at
14+
- unique: title
15+
- unique: title, parent_post_id
16+
- spatialIndex: location
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class CreatePostsTable extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::create('posts', function (Blueprint $table) {
17+
$table->unsignedInteger('id');
18+
$table->string('title');
19+
$table->unsignedBigInteger('parent_post_id');
20+
$table->unsignedBigInteger('author_id');
21+
$table->timestamp('published_at')->nullable();
22+
$table->unsignedInteger('word_count');
23+
$table->geometry('location');
24+
$table->primary('id');
25+
$table->index('author_id');
26+
$table->index(['author_id', 'published_at']);
27+
$table->unique('title');
28+
$table->unique(['title', 'parent_post_id']);
29+
$table->spatialIndex('location');
30+
$table->timestamps();
31+
});
32+
}
33+
34+
/**
35+
* Reverse the migrations.
36+
*
37+
* @return void
38+
*/
39+
public function down()
40+
{
41+
Schema::dropIfExists('posts');
42+
}
43+
}

0 commit comments

Comments
 (0)