Skip to content

Commit

Permalink
Add support for Microsoft SQL
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronhuisinga committed Jan 18, 2024
1 parent ae19849 commit 0f7fca4
Showing 1 changed file with 47 additions and 12 deletions.
59 changes: 47 additions & 12 deletions src/Searchable.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,14 @@ trait Searchable
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $search
* @param int $limit
* @param string|null|Closure $restriction
*
* @return \Illuminate\Database\Eloquent\Builder
*
* @see search()
*/
public function scopeSearch(Builder $query, $search, $restriction = null)
public function scopeSearch(Builder $query, $search, $limit = 25, $restriction = null)
{
$this->searchable = $this->toSearchableArray();

Expand Down Expand Up @@ -110,7 +111,7 @@ public function scopeSearch(Builder $query, $search, $restriction = null)
}

$this->addSelectsToQuery($cloned_query, $selects);
$this->filterQueryWithRelevance($cloned_query, $relevance_count);
$this->filterQueryWithRelevance($cloned_query, $relevance_count, $limit);
$this->makeGroupBy($cloned_query);

if ($restriction instanceof Closure) {
Expand All @@ -126,6 +127,10 @@ public function scopeSearch(Builder $query, $search, $restriction = null)

$this->mergeQueries($cloned_query, $query);

if ($this->getDatabaseDriver() === 'sqlsrv') {
$query->whereRaw('CAST(relevance AS NUMERIC(10,2)) >= ' . number_format($this->threshold, 2, '.', ''));
}

return $query;
}

Expand Down Expand Up @@ -224,7 +229,7 @@ protected function getMatchers()
unset($matchers['exactFullMatcher'], $matchers['exactInStringMatcher']);
}

if ($this->getDatabaseDriver() === 'sqlite') {
if (in_array($this->getDatabaseDriver(), ['sqlite', 'sqlsrv'], true)) {
unset($matchers['similarStringMatcher']);
}

Expand All @@ -243,6 +248,20 @@ protected function getDatabaseDriver()
return config('database.connections.' . $key . '.driver');
}

/**
* Returns the delimiter to use for the current database driver.
*
* @return string
*/
protected function getDelimiter()
{
if ($this->getDatabaseDriver() === 'sqlsrv') {
return '"';
}

return '`';
}

/**
* Returns the search columns.
*
Expand Down Expand Up @@ -347,7 +366,7 @@ protected function getSearchQuery($column, $relevance)
*/
protected function createMatcher($column, $relevance)
{
$formatted = '`' . str_replace('.', '`.`', $column) . '`';
$formatted = $this->getDelimiter() . str_replace('.', "{$this->getDelimiter()}.{$this->getDelimiter()}", $column) . $this->getDelimiter();

if (isset($this->searchable['mutations'][$column])) {
$formatted = $this->searchable['mutations'][$column] . '(' . $formatted . ')';
Expand Down Expand Up @@ -406,9 +425,9 @@ protected function getFullTextColumns()
protected function fullTextMatcher($column, $relevance)
{
$this->search_bindings[] = implode(' ', $this->orderedWords);
$column = str_replace('.', '`.`', $column);
$column = str_replace('.', "{$this->getDelimiter()}.{$this->getDelimiter()}", $column);

$this->matcherQuery = "(MATCH(`$column`) AGAINST (?) * $relevance * 2)";
$this->matcherQuery = "(MATCH({$this->getDelimiter()}$column{$this->getDelimiter()}) AGAINST (?) * $relevance * 2)";
}

/**
Expand All @@ -427,12 +446,20 @@ protected function addSelectsToQuery(Builder $query, array $selects)
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param int $relevance_count
* @param int|null $limit
*/
protected function filterQueryWithRelevance(Builder $query, $relevance_count)
protected function filterQueryWithRelevance(Builder $query, $relevance_count, $limit)
{
if ($limit === null) {
$limit = 25;
}

$this->threshold = $relevance_count * (count($this->getColumns()) / 6) * (count($this->getMatchers()) / 6);

$query->havingRaw('relevance >= ' . number_format($this->threshold, 2, '.', ''));
$query->limit($limit);
if ($this->getDatabaseDriver() !== 'sqlsrv') {
$query->havingRaw('relevance >= ' . number_format($this->threshold, 2, '.', ''));
}
$query->orderBy('relevance', 'desc');
}

Expand All @@ -443,6 +470,10 @@ protected function filterQueryWithRelevance(Builder $query, $relevance_count)
*/
protected function makeGroupBy(Builder $query)
{
if ($this->getDatabaseDriver() === 'sqlsrv') {
return;
}

if ($groupBy = $this->getGroupBy()) {
$query->groupBy($groupBy);
} else {
Expand Down Expand Up @@ -562,9 +593,9 @@ protected function consecutiveCharactersMatcher($query, $column, $relevance)
$this->searchString = '%' . implode('%', str_split(preg_replace('/[^0-9a-zA-Z]/', '', $query))) . '%';
$this->search_bindings[] = $this->searchString;
$this->search_bindings[] = $query;
$column = str_replace('.', '`.`', $column);
$column = str_replace('.', "{$this->getDelimiter()}.{$this->getDelimiter()}", $column);

$this->matcherQuery = "CASE WHEN REPLACE(`$column`, '\.', '') $this->operator ? THEN ROUND($relevance * ( {$this->getLengthMethod()}( ? ) / {$this->getLengthMethod()}( REPLACE(`$column`, ' ', '') ))) ELSE 0 END";
$this->matcherQuery = "CASE WHEN REPLACE({$this->getDelimiter()}$column{$this->getDelimiter()}, '\.', '') $this->operator ? THEN ROUND($relevance * ( {$this->getLengthMethod()}( ? ) / {$this->getLengthMethod()}( REPLACE({$this->getDelimiter()}$column{$this->getDelimiter()}, ' ', '') )), 0) ELSE 0 END";
}

/**
Expand All @@ -578,6 +609,10 @@ protected function getLengthMethod()
return 'LENGTH';
}

if ($this->getDatabaseDriver() === 'sqlsrv') {
return 'LEN';
}

return 'CHAR_LENGTH';
}

Expand Down Expand Up @@ -626,9 +661,9 @@ protected function timesInStringMatcher($query, $column, $relevance)
{
$this->search_bindings[] = $query;
$this->search_bindings[] = $query;
$column = str_replace('.', '`.`', $column);
$column = str_replace('.', "{$this->getDelimiter()}.{$this->getDelimiter()}", $column);

$this->matcherQuery = "($relevance * ROUND(({$this->getLengthMethod()}(COALESCE(`$column`, '')) - {$this->getLengthMethod()}( REPLACE( LOWER(COALESCE(`$column`, '')), lower(?), ''))) / LENGTH(?)))";
$this->matcherQuery = "($relevance * ROUND(({$this->getLengthMethod()}(COALESCE({$this->getDelimiter()}$column{$this->getDelimiter()}, '')) - {$this->getLengthMethod()}( REPLACE( LOWER(COALESCE({$this->getDelimiter()}$column{$this->getDelimiter()}, '')), lower(?), ''))) / {$this->getLengthMethod()}(?), 0))";
}

/**
Expand Down

0 comments on commit 0f7fca4

Please sign in to comment.