Skip to content

Commit

Permalink
feat: add typesense connector (#7282)
Browse files Browse the repository at this point in the history
  • Loading branch information
asbiin authored Nov 15, 2024
1 parent a809ecb commit 0400350
Show file tree
Hide file tree
Showing 15 changed files with 678 additions and 78 deletions.
16 changes: 11 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,20 @@ [email protected]
MAIL_REPLY_TO_NAME="${APP_NAME}"

# Search
# We use Laravel Scout to do full-text search.
# Read config/scout.php for more information.
# Note that you have to use Meilisearch, Algolia or the database driver to enable
# search in Monica. Searching requires a queue to be configured.
## We use Laravel Scout to do full-text search.
## Read config/scout.php for more information.
## Note that you have to use: 'meilisearch', 'typesense', 'algolia' or the 'database'
## driver to enable search in Monica. Searching requires a queue to be configured.
SCOUT_DRIVER=database
SCOUT_QUEUE=true
MEILISEARCH_HOST=
## If you never intend to use the 'database' driver, you can set this value to false:
FULL_TEXT_INDEX=true
## Meilisearch settings
MEILISEARCH_URL=
MEILISEARCH_KEY=
## Typesense settings
TYPESENSE_HOST=
TYPESENSE_API_KEY=

# Notification channels
TELEGRAM_BOT_TOKEN=
Expand Down
2 changes: 1 addition & 1 deletion .env.example.sail
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ MAIL_REPLY_TO_NAME="${APP_NAME}"

SCOUT_DRIVER=meilisearch
SCOUT_QUEUE=true
MEILISEARCH_HOST=http://meilisearch:7700
MEILISEARCH_URL=http://meilisearch:7700
MEILISEARCH_KEY=
MEILISEARCH_NO_ANALYTICS=false
13 changes: 8 additions & 5 deletions app/Console/Commands/SetupScout.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Console\Commands;

use App\Helpers\ScoutHelper;
use Illuminate\Console\Command;
use Illuminate\Console\ConfirmableTrait;
use Symfony\Component\Console\Attribute\AsCommand;
Expand Down Expand Up @@ -49,17 +50,18 @@ public function handle(): void
*/
protected function scoutConfigure(): void
{
if (config('scout.driver') === 'meilisearch' && config('scout.meilisearch.host') !== '') {
$this->artisan('☐ Updating indexes on Meilisearch', 'scout:sync-index-settings', ['--verbose' => true]);
if (ScoutHelper::isIndexed()) {
$this->artisan('☐ Updating indexes', 'scout:sync-index-settings', ['--verbose' => true]);
}
}

/**
* Import models.
* Flush indexes.
*/
protected function scoutFlush(): void
{
if (config('scout.driver') !== null && $this->option('flush')) {
if ($this->option('flush') && ScoutHelper::isIndexed()) {
// Using meilisearch config for any driver
foreach (config('scout.meilisearch.index-settings') as $index => $settings) {
$name = (new $index)->getTable();
$this->artisan("☐ Flush {$name} index", 'scout:flush', ['model' => $index, '--verbose' => true]);
Expand All @@ -74,7 +76,8 @@ protected function scoutFlush(): void
*/
protected function scoutImport(): void
{
if (config('scout.driver') !== null && $this->option('import')) {
if ($this->option('import') && ScoutHelper::isIndexed()) {
// Using meilisearch config for any driver
foreach (config('scout.meilisearch.index-settings') as $index => $settings) {
$name = (new $index)->getTable();
$this->artisan("☐ Import {$name}", 'scout:import', ['model' => $index, '--verbose' => true]);
Expand Down
65 changes: 61 additions & 4 deletions app/Helpers/ScoutHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,84 @@

namespace App\Helpers;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class ScoutHelper
{
/**
* When updating a model, this method determines if we should update the search index.
*
* @return bool
*
* @codeCoverageIgnore
*/
public static function activated()
public static function isActivated(): bool
{
switch (config('scout.driver')) {
case 'algolia':
return config('scout.algolia.id') !== '';
case 'meilisearch':
return config('scout.meilisearch.host') !== '';
return config('scout.meilisearch.key') !== '';
case 'typesense':
return config('scout.typesense.client-settings.api_key') !== '';
case 'database':
case 'collection':
return true;
default:
return false;
}
}

/**
* Test if the driver requires indexes.
*
* @codeCoverageIgnore
*/
public static function isIndexed(): bool
{
switch (config('scout.driver')) {
case 'algolia':
return config('scout.algolia.id') !== '';
case 'meilisearch':
return config('scout.meilisearch.key') !== '';
case 'typesense':
return config('scout.typesense.client-settings.api_key') !== '';
default:
return false;
}
}

/**
* Test if the driver supports full text indexes.
*
* @codeCoverageIgnore
*/
public static function isFullTextIndex(): bool
{
return config('scout.full_text_index') && in_array(DB::connection()->getDriverName(), ['mysql', 'pgsql']);
}

/**
* Get id and basic elements of this model.
*
* @codeCoverageIgnore
*/
public static function id(Model $model): array
{
if (config('scout.driver') === 'database') {
return [];
}

$id = $model->getKey();

if ($id !== null && $model->getKeyType() === 'string' || config('scout.driver') === 'typesense') {
$id = (string) $id;
}

return [
'id' => $id,
'vault_id' => (string) $model->getAttribute('vault_id'),
'created_at' => (int) optional($model->getAttribute(Model::CREATED_AT))->timestamp,
'updated_at' => (int) optional($model->getAttribute(Model::UPDATED_AT))->timestamp,
];
}
}
25 changes: 10 additions & 15 deletions app/Models/Contact.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Laravel\Scout\Attributes\SearchUsingFullText;
use Laravel\Scout\Attributes\SearchUsingPrefix;
use Laravel\Scout\Searchable;

class Contact extends VCardResource
Expand Down Expand Up @@ -83,22 +82,18 @@ class Contact extends VCardResource
/**
* Get the indexable data array for the model.
*
*
* @codeCoverageIgnore
*/
#[SearchUsingPrefix(['id', 'vault_id'])]
#[SearchUsingFullText(['first_name', 'last_name', 'middle_name', 'nickname', 'maiden_name'])]
#[SearchUsingFullText(['first_name', 'last_name', 'middle_name', 'nickname', 'maiden_name'], ['expanded' => true])]
public function toSearchableArray(): array
{
return [
'id' => $this->id,
'vault_id' => $this->vault_id,
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'middle_name' => $this->middle_name,
'nickname' => $this->nickname,
'maiden_name' => $this->maiden_name,
];
return array_merge(ScoutHelper::id($this), [
'first_name' => $this->first_name ?? '',
'last_name' => $this->last_name ?? '',
'middle_name' => $this->middle_name ?? '',
'nickname' => $this->nickname ?? '',
'maiden_name' => $this->maiden_name ?? '',
]);
}

/**
Expand All @@ -120,7 +115,7 @@ public function scopeActive(Builder $query): Builder
}

/**
* Used to delete related objects from Meilisearch/Algolia instance.
* Used to delete related objects from scout driver instance.
*/
protected static function boot(): void
{
Expand All @@ -138,7 +133,7 @@ protected static function boot(): void
*/
public function searchIndexShouldBeUpdated()
{
return ScoutHelper::activated();
return ScoutHelper::isActivated();
}

/**
Expand Down
15 changes: 5 additions & 10 deletions app/Models/Group.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laravel\Scout\Attributes\SearchUsingFullText;
use Laravel\Scout\Attributes\SearchUsingPrefix;
use Laravel\Scout\Searchable;

class Group extends VCardResource
Expand Down Expand Up @@ -53,18 +52,14 @@ public function uniqueIds()
/**
* Get the indexable data array for the model.
*
*
* @codeCoverageIgnore
*/
#[SearchUsingPrefix(['id', 'vault_id'])]
#[SearchUsingFullText(['name'])]
#[SearchUsingFullText(['name'], ['expanded' => true])]
public function toSearchableArray(): array
{
return [
'id' => $this->id,
'vault_id' => $this->vault_id,
'name' => $this->name,
];
return array_merge(ScoutHelper::id($this), [
'name' => $this->name ?? '',
]);
}

/**
Expand All @@ -74,7 +69,7 @@ public function toSearchableArray(): array
*/
public function searchIndexShouldBeUpdated()
{
return ScoutHelper::activated();
return ScoutHelper::isActivated();
}

/**
Expand Down
2 changes: 1 addition & 1 deletion app/Models/Loan.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class Loan extends Model
*/
public function searchIndexShouldBeUpdated()
{
return ScoutHelper::activated();
return ScoutHelper::isActivated();
}

/**
Expand Down
19 changes: 7 additions & 12 deletions app/Models/Note.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Laravel\Scout\Attributes\SearchUsingFullText;
use Laravel\Scout\Attributes\SearchUsingPrefix;
use Laravel\Scout\Searchable;

class Note extends Model
Expand All @@ -33,20 +32,16 @@ class Note extends Model
/**
* Get the indexable data array for the model.
*
*
* @codeCoverageIgnore
*/
#[SearchUsingPrefix(['id', 'vault_id'])]
#[SearchUsingFullText(['title', 'body'])]
#[SearchUsingFullText(['title', 'body'], ['expanded' => true])]
public function toSearchableArray(): array
{
return [
'id' => $this->id,
'vault_id' => $this->vault_id,
'contact_id' => $this->contact_id,
'title' => $this->title,
'body' => $this->body,
];
return array_merge(ScoutHelper::id($this), [
'contact_id' => (string) $this->contact_id,
'title' => $this->title ?? '',
'body' => $this->body ?? '',
]);
}

/**
Expand All @@ -56,7 +51,7 @@ public function toSearchableArray(): array
*/
public function searchIndexShouldBeUpdated()
{
return ScoutHelper::activated();
return ScoutHelper::isActivated();
}

/**
Expand Down
2 changes: 1 addition & 1 deletion app/Models/Vault.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class Vault extends Model
];

/**
* Used to delete related objects from Meilisearch/Algolia instance.
* Used to delete related objects from scout driver instance.
*/
protected static function boot(): void
{
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"stevebauman/location": "^7.0",
"thecodingmachine/safe": "^2.5",
"tightenco/ziggy": "2.3.0",
"typesense/typesense-php": "^4.9",
"uploadcare/uploadcare-php": "^4.1"
},
"require-dev": {
Expand Down
Loading

0 comments on commit 0400350

Please sign in to comment.