Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 5 additions & 17 deletions packages/support/src/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ function generate_loading_indicator_html(?ComponentAttributeBag $attributes = nu
/**
* @internal This function is only to be used internally by Filament and is subject to change at any time. Please do not use this function in your own code.
*/
function generate_search_column_expression(string $column, ?bool $isSearchForcedCaseInsensitive, Connection $databaseConnection): string | Expression
function generate_search_column_expression(string $column, ?bool $isSearchForcedCaseInsensitive, Connection $databaseConnection): Expression
{
$driverName = $databaseConnection->getDriverName();

Expand Down Expand Up @@ -272,11 +272,11 @@ function generate_search_column_expression(string $column, ?bool $isSearchForced

$isSearchForcedCaseInsensitive ??= match ($driverName) {
'pgsql' => true,
default => str($column)->contains('json_extract('),
default => str($column)->contains('json_extract(') || str($column)->contains('->'),
};

if ($isSearchForcedCaseInsensitive) {
if (in_array($driverName, ['mysql', 'mariadb'], true) && str($column)->contains('->') && ! str($column)->startsWith('json_extract(')) {
if (in_array($driverName, ['mysql', 'mariadb', 'sqlite'], true) && str($column)->contains('->') && ! str($column)->startsWith('json_extract(')) {
[$field, $path] = invade($databaseConnection->getQueryGrammar())->wrapJsonFieldAndPath($column); /** @phpstan-ignore-line */
$column = "json_extract({$field}{$path})";
}
Expand All @@ -290,14 +290,7 @@ function generate_search_column_expression(string $column, ?bool $isSearchForced
$column = "{$column} collate {$collation}";
}

if (
str($column)->contains('(') || // This checks if the column name probably contains a raw expression like `lower()` or `json_extract()`.
filled($collation)
) {
return new Expression($column);
}

return $column;
return new Expression($column);
}
}

Expand All @@ -307,12 +300,7 @@ function generate_search_column_expression(string $column, ?bool $isSearchForced
*/
function generate_search_term_expression(string $search, ?bool $isSearchForcedCaseInsensitive, Connection $databaseConnection): string
{
$isSearchForcedCaseInsensitive ??= match ($databaseConnection->getDriverName()) {
'pgsql' => true,
default => false,
};

if (! $isSearchForcedCaseInsensitive) {
if ($isSearchForcedCaseInsensitive === false) {
return $search;
}

Expand Down
26 changes: 21 additions & 5 deletions packages/tables/src/Table/Concerns/CanSearchRecords.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ trait CanSearchRecords

protected ?Closure $searchUsing = null;

protected bool | Closure | null $isSearchForcedCaseInsensitive = null;

public function persistSearchInSession(bool | Closure $condition = true): static
{
$this->persistsSearchInSession = $condition;
Expand Down Expand Up @@ -205,29 +207,31 @@ public function applyExtraSearchConstraints(Builder $query, string $search, bool

$model = $query->getModel();

$nonTranslatableSearch = generate_search_term_expression($search, isSearchForcedCaseInsensitive: false, databaseConnection: $databaseConnection);
$isSearchForcedCaseInsensitive = $this->isSearchForcedCaseInsensitive();

$nonTranslatableSearch = generate_search_term_expression($search, isSearchForcedCaseInsensitive: $isSearchForcedCaseInsensitive, databaseConnection: $databaseConnection);

$translatableContentDriver = $this->getLivewire()->makeFilamentTranslatableContentDriver();

$query->when(
$translatableContentDriver?->isAttributeTranslatable($model::class, attribute: $column),
fn (Builder $query): Builder => $translatableContentDriver->applySearchConstraintToQuery($query, $column, $search, $whereClause, isSearchForcedCaseInsensitive: false),
fn (Builder $query): Builder => $translatableContentDriver->applySearchConstraintToQuery($query, $column, $search, $whereClause, isSearchForcedCaseInsensitive: $isSearchForcedCaseInsensitive),
fn (Builder $query) => $query->when(
$this->getExtraSearchableColumnRelationship($column, $query->getModel()),
fn (Builder $query): Builder => $query->{"{$whereClause}Relation"}(
(string) str($column)->beforeLast('.'),
generate_search_column_expression((string) str($column)->afterLast('.'), isSearchForcedCaseInsensitive: false, databaseConnection: $databaseConnection),
generate_search_column_expression((string) str($column)->afterLast('.'), isSearchForcedCaseInsensitive: $isSearchForcedCaseInsensitive, databaseConnection: $databaseConnection),
'like',
"%{$nonTranslatableSearch}%",
),
function (Builder $query) use ($databaseConnection, $nonTranslatableSearch, $column, $whereClause): Builder {
function (Builder $query) use ($databaseConnection, $nonTranslatableSearch, $column, $whereClause, $isSearchForcedCaseInsensitive): Builder {
// Treat the missing "relationship" as a JSON column if dot notation is used in the column name.
if (str($column)->contains('.')) {
$column = (string) str($column)->replace('.', '->');
}

return $query->{$whereClause}(
generate_search_column_expression($column, isSearchForcedCaseInsensitive: false, databaseConnection: $databaseConnection),
generate_search_column_expression($column, isSearchForcedCaseInsensitive: $isSearchForcedCaseInsensitive, databaseConnection: $databaseConnection),
'like',
"%{$nonTranslatableSearch}%",
);
Expand Down Expand Up @@ -298,4 +302,16 @@ public function callSearchUsing(Builder $query, string $search): void
'search' => $search,
]);
}

public function forceSearchCaseInsensitive(bool | Closure | null $condition = true): static
{
$this->isSearchForcedCaseInsensitive = $condition;

return $this;
}

public function isSearchForcedCaseInsensitive(): ?bool
{
return $this->evaluate($this->isSearchForcedCaseInsensitive);
}
}