Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Seal Loupe Adapter Laravel Package

cmsig/seal-loupe-adapter

Loupe adapter for the SEAL search engine: write indexed documents into a Loupe SQLite instance. Install via Composer and configure through code or a loupe:// DSN (e.g., loupe://var/indexes/). Part of the cmsig/search project.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install Dependencies

    composer require cmsig/seal cmsig/seal-loupe-adapter
    

    Ensure loupe-php/loupe is also installed (handled as a dependency).

  2. Basic Engine Initialization

    use CmsIg\Seal\Engine;
    use CmsIg\Seal\Adapter\Loupe\LoupeAdapter;
    use Loupe\Loupe\LoupeFactory;
    
    $loupeFactory = new LoupeFactory();
    $adapter = new LoupeAdapter(new LoupeHelper($loupeFactory, 'storage/loupe'));
    $engine = new Engine($adapter, $schema);
    
  3. First Use Case: Indexing Documents

    $engine->index('documents', [
        'id' => 1,
        'title' => 'Laravel SEO Guide',
        'content' => '...',
    ]);
    

Where to Look First

  • LoupeHelper: Configures the SQLite storage path (default: var/indexes/).
  • LoupeAdapter: Bridges SEAL’s abstraction to Loupe’s SQLite backend.
  • SEAL Docs: cmsig/search for schema definitions and engine patterns.

Implementation Patterns

Workflows

  1. Schema-Driven Indexing Define a schema (e.g., DocumentSchema) with fields like:

    $schema = new DocumentSchema();
    $schema->addTextField('title');
    $schema->addTextField('content');
    

    Pass it to the Engine constructor.

  2. Querying with SEAL

    $results = $engine->search('documents', 'Laravel SEO', [
        'limit' => 10,
        'fields' => ['title', 'content'],
    ]);
    
  3. Bulk Operations

    $engine->bulkIndex('documents', [
        ['id' => 1, 'title' => 'Post 1'],
        ['id' => 2, 'title' => 'Post 2'],
    ]);
    

Integration Tips

  • Laravel Service Provider Bind the engine in AppServiceProvider:

    $this->app->singleton(Engine::class, function ($app) {
        $loupeFactory = new LoupeFactory();
        return new Engine(
            new LoupeAdapter(new LoupeHelper($loupeFactory, storage_path('loupe'))),
            $app->make(DocumentSchema::class)
        );
    });
    
  • DSN Configuration Use .env for flexibility:

    SEAL_LOUPE_DSN=loupe://storage/loupe
    

    Parse it in a helper:

    $dsn = parse_url(env('SEAL_LOUPE_DSN'));
    $adapter = new LoupeAdapter(new LoupeHelper($loupeFactory, $dsn['path']));
    
  • Field Mapping Customize Loupe’s field types via LoupeHelper:

    $helper = new LoupeHelper($loupeFactory, 'storage/loupe');
    $helper->setFieldType('content', 'text'); // Override default
    

Gotchas and Tips

Pitfalls

  1. SQLite Locking

    • Loupe uses SQLite, which can block during concurrent writes.
    • Fix: Use WRITE_AHEAD_LOCKING mode in LoupeFactory:
      $loupeFactory = new LoupeFactory(['mode' => 'wal']);
      
  2. Schema Mismatches

    • LoupeAdapter expects SEAL schemas to map cleanly to Loupe’s field types.
    • Debug: Check LoupeHelper::getFieldType() for unexpected conversions.
  3. Path Permissions

    • Ensure the storage directory (var/indexes/) is writable by the web server.
    • Tip: Use storage_path('loupe') in Laravel to avoid hardcoding.
  4. Case Sensitivity

    • Loupe’s SQLite backend is case-sensitive by default.
    • Workaround: Configure collation in LoupeFactory:
      $loupeFactory = new LoupeFactory(['collation' => 'NOCASE']);
      

Debugging

  • Enable Loupe Logging

    $loupeFactory = new LoupeFactory(['debug' => true]);
    

    Logs appear in storage/logs/loupe.log (Laravel) or stdout.

  • Inspect SQLite Directly

    sqlite3 storage/loupe/index.db ".tables"  # List indexes
    sqlite3 storage/loupe/index.db "SELECT * FROM documents;"  # Query raw data
    

Extension Points

  1. Custom Field Processors Extend LoupeHelper to transform SEAL fields before indexing:

    class CustomLoupeHelper extends LoupeHelper {
        public function getFieldType($fieldName) {
            if ($fieldName === 'slug') return 'keyword';
            return parent::getFieldType($fieldName);
        }
    }
    
  2. Query Modifiers Override LoupeAdapter::search() to inject Loupe-specific syntax:

    $adapter->search($index, $query, [
        'boost' => ['title' => 2.0], // Loupe-specific
    ]);
    
  3. Multi-Index Management Use separate LoupeFactory instances for isolated indexes:

    $factory1 = new LoupeFactory(['path' => 'storage/loupe/index1']);
    $factory2 = new LoupeFactory(['path' => 'storage/loupe/index2']);
    

Performance Tips

  • Batch Indexing Reduce SQLite overhead by batching inserts:

    $engine->bulkIndex('documents', array_chunk($documents, 50));
    
  • Index Optimization Rebuild Loupe’s internal indexes periodically:

    $loupeFactory->getIndex('documents')->optimize();
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime