Skip to content

Commit 89f3136

Browse files
abnegateclaude
andcommitted
Merge branch 'main' into feat-query-lib
Bring in SQLite FTS5 + PCRE + upsert + PRAGMA introspection from PR #870, translated to the typed Attribute/Index/Relationship API and the Capability enum. SQLite gains: - FTS5-backed fulltext indexes (createFulltextIndex / dropFulltextIndexById / resolveFulltextTableById, FTS5-aware deleteCollection / deleteIndex / getSizeOfCollection, attribute-aware FTS routing) - PHP REGEXP UDF with a bounded LRU pattern cache, gating Capability::PCRE dynamically once registered - BEGIN IMMEDIATE writer serialisation - PRAGMA-based getSchemaAttributes / getSchemaIndexes - Per-statement createRelationship / updateRelationship / deleteRelationship (SQLite PDO can't run multi-statement strings) - setEmulateMySQL flag gating MariaDB-shape emulation across createCollection (_tenant column type), getSchemaAttributes (column-info shape), and updateAttribute (resize-down with TruncateException guard) - SQL.php gains getSQLConditionsForCollection threading $forCollection so the FTS5 routing surfaces consistently across MariaDB / Postgres / SQLite phpstan-baseline shrinks 18 entries — the typed getPDO override and narrowed mixed flow on the new paths resolve the prior ignores. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2 parents 96855b5 + a1bb3e2 commit 89f3136

7 files changed

Lines changed: 1559 additions & 286 deletions

File tree

phpstan-baseline.neon

Lines changed: 0 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -516,114 +516,6 @@ parameters:
516516
count: 1
517517
path: src/Database/Adapter/SQL.php
518518

519-
-
520-
message: '#^Call to an undefined method object\:\:beginTransaction\(\)\.$#'
521-
identifier: method.notFound
522-
count: 1
523-
path: src/Database/Adapter/SQLite.php
524-
525-
-
526-
message: '#^Call to an undefined method object\:\:inTransaction\(\)\.$#'
527-
identifier: method.notFound
528-
count: 1
529-
path: src/Database/Adapter/SQLite.php
530-
531-
-
532-
message: '#^Call to an undefined method object\:\:prepare\(\)\.$#'
533-
identifier: method.notFound
534-
count: 14
535-
path: src/Database/Adapter/SQLite.php
536-
537-
-
538-
message: '#^Call to an undefined method object\:\:query\(\)\.$#'
539-
identifier: method.notFound
540-
count: 1
541-
path: src/Database/Adapter/SQLite.php
542-
543-
-
544-
message: '#^Call to an undefined method object\:\:rollBack\(\)\.$#'
545-
identifier: method.notFound
546-
count: 1
547-
path: src/Database/Adapter/SQLite.php
548-
549-
-
550-
message: '#^Cannot access offset 0 on mixed\.$#'
551-
identifier: offsetAccess.nonOffsetAccessible
552-
count: 1
553-
path: src/Database/Adapter/SQLite.php
554-
555-
-
556-
message: '#^Cannot call method bindParam\(\) on mixed\.$#'
557-
identifier: method.nonObject
558-
count: 2
559-
path: src/Database/Adapter/SQLite.php
560-
561-
-
562-
message: '#^Cannot call method bindValue\(\) on mixed\.$#'
563-
identifier: method.nonObject
564-
count: 3
565-
path: src/Database/Adapter/SQLite.php
566-
567-
-
568-
message: '#^Cannot call method closeCursor\(\) on mixed\.$#'
569-
identifier: method.nonObject
570-
count: 2
571-
path: src/Database/Adapter/SQLite.php
572-
573-
-
574-
message: '#^Cannot call method execute\(\) on mixed\.$#'
575-
identifier: method.nonObject
576-
count: 14
577-
path: src/Database/Adapter/SQLite.php
578-
579-
-
580-
message: '#^Cannot call method fetch\(\) on mixed\.$#'
581-
identifier: method.nonObject
582-
count: 3
583-
path: src/Database/Adapter/SQLite.php
584-
585-
-
586-
message: '#^Cannot call method fetchAll\(\) on mixed\.$#'
587-
identifier: method.nonObject
588-
count: 1
589-
path: src/Database/Adapter/SQLite.php
590-
591-
-
592-
message: '#^Cannot call method fetchColumn\(\) on mixed\.$#'
593-
identifier: method.nonObject
594-
count: 2
595-
path: src/Database/Adapter/SQLite.php
596-
597-
-
598-
message: '#^Method Utopia\\Database\\Adapter\\SQLite\:\:createIndex\(\) should return bool but returns mixed\.$#'
599-
identifier: return.type
600-
count: 1
601-
path: src/Database/Adapter/SQLite.php
602-
603-
-
604-
message: '#^Method Utopia\\Database\\Adapter\\SQLite\:\:deleteAttribute\(\) should return bool but returns mixed\.$#'
605-
identifier: return.type
606-
count: 1
607-
path: src/Database/Adapter/SQLite.php
608-
609-
-
610-
message: '#^Method Utopia\\Database\\Adapter\\SQLite\:\:deleteIndex\(\) should return bool but returns mixed\.$#'
611-
identifier: return.type
612-
count: 1
613-
path: src/Database/Adapter/SQLite.php
614-
615-
-
616-
message: '#^Method Utopia\\Database\\Adapter\\SQLite\:\:startTransaction\(\) should return bool but returns mixed\.$#'
617-
identifier: return.type
618-
count: 1
619-
path: src/Database/Adapter/SQLite.php
620-
621-
-
622-
message: '#^Parameter \#1 \$array of function array_diff expects an array of values castable to string, array\<mixed, mixed\> given\.$#'
623-
identifier: argument.type
624-
count: 1
625-
path: src/Database/Adapter/SQLite.php
626-
627519
-
628520
message: '#^Parameter \#1 \$input of class Utopia\\Database\\Document constructor expects array\<string, mixed\>, array\<mixed, mixed\> given\.$#'
629521
identifier: argument.type

src/Database/Adapter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ abstract class Adapter implements Feature\Attributes, Feature\Collections, Featu
7373
protected Authorization $authorization;
7474

7575
/** @var array<string, true>|null */
76-
private ?array $capabilitySet = null;
76+
protected ?array $capabilitySet = null;
7777

7878
/**
7979
* Check if this adapter supports a given capability.

src/Database/Adapter/Postgres.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,7 +1580,7 @@ protected function handleObjectQueries(Query $query, array &$binds, string $attr
15801580
*
15811581
* @throws Exception
15821582
*/
1583-
protected function getSQLCondition(Query $query, array &$binds): string
1583+
protected function getSQLCondition(Query $query, array &$binds, ?string $forCollection = null): string
15841584
{
15851585
$query->setAttribute($this->getInternalKeyForAttribute($query->getAttribute()));
15861586
$isNestedObjectAttribute = $query->isObjectAttribute() && \str_contains($query->getAttribute(), '.');
@@ -1611,7 +1611,7 @@ protected function getSQLCondition(Query $query, array &$binds): string
16111611
/** @var iterable<Query> $nestedQueries */
16121612
$nestedQueries = $query->getValue();
16131613
foreach ($nestedQueries as $q) {
1614-
$conditions[] = $this->getSQLCondition($q, $binds);
1614+
$conditions[] = $this->getSQLCondition($q, $binds, $forCollection);
16151615
}
16161616

16171617
$method = strtoupper($query->getMethod()->value);

src/Database/Adapter/SQL.php

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,18 @@ protected function getFloatPrecision(float $value): string
219219
return sprintf('%.'.$this->floatPrecision.'F', $value);
220220
}
221221

222+
/**
223+
* Build conditions threading `$name` to per-query builders so adapter
224+
* overrides (SQLite FTS5 routing) can resolve auxiliary tables.
225+
*
226+
* @param array<Query> $queries
227+
* @param array<string,mixed> $binds
228+
*/
229+
protected function getSQLConditionsForCollection(string $name, array $queries, array &$binds, string $separator = 'AND'): string
230+
{
231+
return $this->getSQLConditions($queries, $binds, $separator, $name);
232+
}
233+
222234
/**
223235
* Get the hostname of the database connection.
224236
*
@@ -4129,10 +4141,11 @@ protected function handleDistanceSpatialQueries(Query $query, array &$binds, str
41294141

41304142
/**
41314143
* @param array<string, mixed> $binds
4144+
* @param ?string $forCollection Filtered collection id (for FTS5 routing).
41324145
*
41334146
* @throws Exception
41344147
*/
4135-
protected function getSQLCondition(Query $query, array &$binds): string
4148+
protected function getSQLCondition(Query $query, array &$binds, ?string $forCollection = null): string
41364149
{
41374150
$query->setAttribute($this->getInternalKeyForAttribute($query->getAttribute()));
41384151

@@ -4153,7 +4166,7 @@ protected function getSQLCondition(Query $query, array &$binds): string
41534166
/** @var iterable<Query> $nestedQueries */
41544167
$nestedQueries = $query->getValue();
41554168
foreach ($nestedQueries as $q) {
4156-
$conditions[] = $this->getSQLCondition($q, $binds);
4169+
$conditions[] = $this->getSQLCondition($q, $binds, $forCollection);
41574170
}
41584171

41594172
$method = strtoupper($query->getMethod()->value);
@@ -4247,11 +4260,12 @@ protected function getSQLCondition(Query $query, array &$binds): string
42474260
* @param array<Query> $queries
42484261
* @param array<string, mixed> $binds
42494262
* @param string $separator The logical operator joining conditions (AND/OR)
4263+
* @param ?string $forCollection See {@see getSQLCondition}.
42504264
* @return string
42514265
*
42524266
* @throws Exception
42534267
*/
4254-
public function getSQLConditions(array $queries, array &$binds, string $separator = 'AND'): string
4268+
public function getSQLConditions(array $queries, array &$binds, string $separator = 'AND', ?string $forCollection = null): string
42554269
{
42564270
$conditions = [];
42574271
foreach ($queries as $query) {
@@ -4262,9 +4276,9 @@ public function getSQLConditions(array $queries, array &$binds, string $separato
42624276
if ($query->isNested()) {
42634277
/** @var array<Query> $nestedQueries */
42644278
$nestedQueries = $query->getValues();
4265-
$conditions[] = $this->getSQLConditions($nestedQueries, $binds, strtoupper($query->getMethod()->value));
4279+
$conditions[] = $this->getSQLConditions($nestedQueries, $binds, strtoupper($query->getMethod()->value), $forCollection);
42664280
} else {
4267-
$conditions[] = $this->getSQLCondition($query, $binds);
4281+
$conditions[] = $this->getSQLCondition($query, $binds, $forCollection);
42684282
}
42694283
}
42704284

0 commit comments

Comments
 (0)