Skip to content

Commit 7137abc

Browse files
authored
Merge pull request #418 from bowphp/refactor/code-base
refactor(console): add index to stub models
2 parents 99bed65 + 7c250de commit 7137abc

14 files changed

Lines changed: 332 additions & 57 deletions

‎src/Console/stubs/model/cache.stub‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class {className} extends Migration
1414
$table->addString('key_name', ['primary' => true, 'size' => 500]);
1515
$table->addText('data');
1616
$table->addDatetime('expire', ['nullable' => true]);
17+
$table->addIndex('expire');
1718
$table->addTimestamps();
1819
});
1920
}

‎src/Console/stubs/model/notification.stub‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class {className} extends Migration
1515
$table->addString('type');
1616
$table->addString('concern_id');
1717
$table->addString('concern_type');
18+
$table->addIndex('concern_id');
19+
$table->addIndex('concern_type');
1820
$table->addText('data');
1921
$table->addDatetime('read_at', ['nullable' => true]);
2022
$table->addTimestamps();

‎src/Console/stubs/model/queue.stub‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ class {className} extends Migration
2222
$table->addDatetime('available_at');
2323
$table->addDatetime('reserved_at', ["nullable" => true, "default" => null]);
2424
$table->addDatetime('created_at');
25+
$table->addIndex('queue');
26+
$table->addIndex('status');
2527
});
2628
}
2729

‎src/Console/stubs/model/session.stub‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class {className} extends Migration
1515
$table->addTimestamp('time');
1616
$table->addText('data');
1717
$table->addString('ip');
18+
$table->addIndex('time');
1819
});
1920
}
2021

‎src/Database/Barry/Concerns/Relationship.php‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,6 @@ public function belongsTo(
4040
return new BelongsTo($related_model, $this, $foreign_key, $local_key);
4141
}
4242

43-
/**
44-
* Get the table key
45-
*
46-
* @return string
47-
*/
48-
abstract public function getKey(): string;
49-
5043
/**
5144
* The belongs to many relative
5245
*
@@ -128,4 +121,11 @@ public function hasOne(
128121

129122
return new HasOne($related_model, $this, $foreign_key, $primary_key);
130123
}
124+
125+
/**
126+
* Get the table key
127+
*
128+
* @return string
129+
*/
130+
abstract public function getKey(): string;
131131
}

‎src/Database/Barry/Relation.php‎

Lines changed: 76 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -16,43 +16,57 @@ abstract class Relation
1616
* @var bool
1717
*/
1818
protected static bool $has_constraints = true;
19+
1920
/**
2021
* Indicate whether the relationships use a pivot table.*.
2122
*
2223
* @var bool
2324
*/
2425
protected static bool $has_pivot = false;
26+
2527
/**
2628
* The foreign key of the parent model.
2729
*
2830
* @var string
2931
*/
3032
protected string $foreign_key;
33+
3134
/**
3235
* The associated key on the parent model.
3336
*
3437
* @var string
3538
*/
3639
protected string $local_key;
40+
3741
/**
3842
* The parent model instance
3943
*
4044
* @var Model
4145
*/
4246
protected Model $parent;
47+
4348
/**
4449
* The related model instance
4550
*
4651
* @var Model
4752
*/
4853
protected Model $related;
54+
4955
/**
5056
* The Bow Query builder
5157
*
5258
* @var QueryBuilder
5359
*/
5460
protected QueryBuilder $query;
5561

62+
/**
63+
* Whether no parent exposed a key during eager loading, in which case the
64+
* relation resolves to nothing without querying the database.
65+
*
66+
* @var bool
67+
*/
68+
protected bool $eager_has_no_keys = false;
69+
5670
/**
5771
* Relation Contractor
5872
*
@@ -84,6 +98,34 @@ public function __construct(Model $related, Model $parent)
8498
*/
8599
abstract public function addConstraints(): void;
86100

101+
/**
102+
* Get the results of the relationship.
103+
*
104+
* @return mixed
105+
*/
106+
abstract public function getResults(): mixed;
107+
108+
/**
109+
* The parent attribute whose value is matched against the related models.
110+
*
111+
* @return string
112+
*/
113+
abstract protected function eagerParentKey(): string;
114+
115+
/**
116+
* The related column queried when eager loading the relation.
117+
*
118+
* @return string
119+
*/
120+
abstract protected function eagerRelatedKey(): string;
121+
122+
/**
123+
* Whether the relation resolves to many related models.
124+
*
125+
* @return bool
126+
*/
127+
abstract protected function eagerIsMany(): bool;
128+
87129
/**
88130
* Get the parent model.
89131
*
@@ -104,24 +146,6 @@ public function getRelated(): Model
104146
return $this->related;
105147
}
106148

107-
/**
108-
* _Call
109-
*
110-
* @param string $method
111-
* @param array $args
112-
* @return mixed
113-
*/
114-
public function __call(string $method, array $args = [])
115-
{
116-
$result = call_user_func_array([$this->query, $method], (array)$args);
117-
118-
if ($result === $this->query) {
119-
return $this;
120-
}
121-
122-
return $result;
123-
}
124-
125149
/**
126150
* Create a new row of the related
127151
*
@@ -135,34 +159,6 @@ public function create(array $attributes): Model
135159
return $this->related->create($attributes);
136160
}
137161

138-
/**
139-
* Get the results of the relationship.
140-
*
141-
* @return mixed
142-
*/
143-
abstract public function getResults(): mixed;
144-
145-
/**
146-
* The parent attribute whose value is matched against the related models.
147-
*
148-
* @return string
149-
*/
150-
abstract protected function eagerParentKey(): string;
151-
152-
/**
153-
* The related column queried when eager loading the relation.
154-
*
155-
* @return string
156-
*/
157-
abstract protected function eagerRelatedKey(): string;
158-
159-
/**
160-
* Whether the relation resolves to many related models.
161-
*
162-
* @return bool
163-
*/
164-
abstract protected function eagerIsMany(): bool;
165-
166162
/**
167163
* Run the given callback with relation constraints disabled.
168164
*
@@ -197,9 +193,17 @@ public function addEagerConstraints(array $parents): void
197193
fn ($value) => !is_null($value)
198194
)));
199195

200-
// Fall back to an impossible match when no parent exposes a key so the
201-
// query stays well-formed and returns nothing.
202-
$this->query->whereIn($this->eagerRelatedKey(), count($keys) > 0 ? $keys : [0]);
196+
// With no keys to match, skip the value-based constraint entirely.
197+
// Injecting a placeholder value (such as 0) is rejected by strongly
198+
// typed columns — e.g. a PostgreSQL uuid primary key raises
199+
// "invalid input syntax for type uuid: 0". getEager() short-circuits.
200+
if (count($keys) === 0) {
201+
$this->eager_has_no_keys = true;
202+
203+
return;
204+
}
205+
206+
$this->query->whereIn($this->eagerRelatedKey(), $keys);
203207
}
204208

205209
/**
@@ -209,6 +213,11 @@ public function addEagerConstraints(array $parents): void
209213
*/
210214
public function getEager(): Collection
211215
{
216+
// No parent exposed a key, so there is nothing to fetch.
217+
if ($this->eager_has_no_keys) {
218+
return new Collection([]);
219+
}
220+
212221
$results = $this->query->get();
213222

214223
return $results instanceof Collection ? $results : new Collection([]);
@@ -240,4 +249,22 @@ public function match(array $parents, Collection $results, string $name): void
240249
);
241250
}
242251
}
252+
253+
/**
254+
* _Call
255+
*
256+
* @param string $method
257+
* @param array $args
258+
* @return mixed
259+
*/
260+
public function __call(string $method, array $args = [])
261+
{
262+
$result = call_user_func_array([$this->query, $method], (array)$args);
263+
264+
if ($result === $this->query) {
265+
return $this;
266+
}
267+
268+
return $result;
269+
}
243270
}

‎src/Database/QueryBuilder.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1587,7 +1587,7 @@ private function execute(string $sql, array $bindings = [], bool $write = true):
15871587
$this->triggerQueryEvent($sql, $ended_at - $start_at, $bindings);
15881588
} catch (\Exception $e) {
15891589
throw new QueryBuilderException(
1590-
'Error executing query: ' . $e->getMessage() . ' | Query: ' . $this->last_query,
1590+
'message: ' . $e->getMessage() . '; query: ' . $this->last_query,
15911591
$this->last_query,
15921592
E_ERROR,
15931593
);

‎tests/Console/__snapshots__/GeneratorDeepTest__test_generate_cache_migration_stubs__1.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class FakeCacheMigration extends Migration
1414
$table->addString('key_name', ['primary' => true, 'size' => 500]);
1515
$table->addText('data');
1616
$table->addDatetime('expire', ['nullable' => true]);
17+
$table->addIndex('expire');
1718
$table->addTimestamps();
1819
});
1920
}

‎tests/Console/__snapshots__/GeneratorDeepTest__test_generate_notification_migration_stubs__1.txt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class FakeNotificationTableMigration extends Migration
1515
$table->addString('type');
1616
$table->addString('concern_id');
1717
$table->addString('concern_type');
18+
$table->addIndex('concern_id');
19+
$table->addIndex('concern_type');
1820
$table->addText('data');
1921
$table->addDatetime('read_at', ['nullable' => true]);
2022
$table->addTimestamps();

‎tests/Console/__snapshots__/GeneratorDeepTest__test_generate_queue_migration_stubs__1.txt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ class QueueTableMigration extends Migration
2222
$table->addDatetime('available_at');
2323
$table->addDatetime('reserved_at', ["nullable" => true, "default" => null]);
2424
$table->addDatetime('created_at');
25+
$table->addIndex('queue');
26+
$table->addIndex('status');
2527
});
2628
}
2729

0 commit comments

Comments
 (0)