{"id":31718220,"url":"https://github.com/lstpsche/search-engine-for-typesense","last_synced_at":"2026-04-02T00:59:47.780Z","repository":{"id":318354528,"uuid":"1067781704","full_name":"lstpsche/search-engine-for-typesense","owner":"lstpsche","description":"ActiveRecord-like Typesense Wrapper gem.","archived":false,"fork":false,"pushed_at":"2026-02-05T21:01:50.000Z","size":1649,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-06T02:56:30.359Z","etag":null,"topics":["gem","rails","search-engine","typesense"],"latest_commit_sha":null,"homepage":"https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lstpsche.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-01T11:35:04.000Z","updated_at":"2026-02-05T20:59:14.000Z","dependencies_parsed_at":"2025-10-08T17:54:55.888Z","dependency_job_id":"de8c3cf5-3caf-4e8c-a641-44ea0487c16f","html_url":"https://github.com/lstpsche/search-engine-for-typesense","commit_stats":null,"previous_names":["lstpsche/typesense-search-engine","lstpsche/search-engine-for-typesense"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/lstpsche/search-engine-for-typesense","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lstpsche%2Fsearch-engine-for-typesense","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lstpsche%2Fsearch-engine-for-typesense/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lstpsche%2Fsearch-engine-for-typesense/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lstpsche%2Fsearch-engine-for-typesense/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lstpsche","download_url":"https://codeload.github.com/lstpsche/search-engine-for-typesense/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lstpsche%2Fsearch-engine-for-typesense/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30180645,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T12:39:21.703Z","status":"ssl_error","status_checked_at":"2026-03-06T12:36:09.819Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gem","rails","search-engine","typesense"],"created_at":"2025-10-09T02:33:17.420Z","updated_at":"2026-04-02T00:59:47.768Z","avatar_url":"https://github.com/lstpsche.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Search Engine for Typesense [![CI][ci-badge]][ci-url] [![Gem][gem-badge]][gem-url] [![Docs][docs-badge]][docs-url]\n[![Typesense](https://img.shields.io/badge/Typesense-Typesense-blue)](https://typesense.org) [![Typesense Ruby gem](https://img.shields.io/badge/Typesense%20Ruby%20gem-TypesenseRubyGem-blue)](https://github.com/typesense/typesense-ruby)\n\nMountless Rails::Engine for [Typesense](https://typesense.org). Expressive Relation/DSL with JOINs, grouping, presets/curation — with strong DX and observability.\n\n\u003e [!NOTE]\n\u003e This project is not affiliated with [Typesense](https://typesense.org) and is a wrapper for the [`typesense` gem](https://github.com/typesense/typesense-ruby).\n\n## Versioning\n\nThe gem version mirrors the Typesense server major/minor it targets. Patch releases are reserved for gem-only fixes and enhancements.\n\nExample: `30.1.x` targets Typesense `30.1`.\n\n## Quickstart\n\n```ruby\n# Gemfile\ngem \"search-engine-for-typesense\"\n```\n\n```ruby\n# config/initializers/search_engine_for_typesense.rb\nSearchEngine.configure do |c|\n  c.host = ENV.fetch(\"TYPESENSE_HOST\", \"localhost\")\n  c.port = 8108\n  c.protocol = \"http\"\n  c.api_key = ENV.fetch(\"TYPESENSE_API_KEY\")\nend\n```\n\n```ruby\nclass SearchEngine::Product \u003c SearchEngine::Base\n  collection :products\n\n  attribute :id, :integer\n  attribute :name, :string\n\n  query_by %i[name brand description]\nend\n\nSearchEngine::Product.where(name: \"milk\").select(:id, :name).limit(5).to_a\n```\n\nSee [Quickstart](https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/quickstart).\n\n### Host app SearchEngine models\n\nBy default, the gem manages a dedicated Zeitwerk loader for your SearchEngine models under `app/search_engine/`. The loader is initialized after Rails so that application models/constants are available, auto-reloads in development, and is eager-loaded in production/test.\n\nCustomize or disable via configuration:\n\n```ruby\n# config/initializers/search_engine.rb\nSearchEngine.configure do |c|\n  # Relative to Rails.root or absolute; set to nil/false to disable\n  c.search_engine_models = 'app/search_engine'\nend\n```\n\n## Usage examples\n\n```ruby\n# Model\nclass SearchEngine::Product \u003c SearchEngine::Base\n  collection \"products\"\n\n  attribute :id, :integer\n  attribute :name, :string\nend\n\n# Basic query\nSearchEngine::Product\n  .where(name: \"milk\")\n  # Explicit query_by always wins over model/global defaults\n  .options(query_by: 'name,brand')\n  .select(:id, :name)\n  .order(price_cents: :asc)\n  .limit(5)\n  .to_a\n\n# JOIN + nested selection\nSearchEngine::Product\n  .joins(:brands)\n  .select(:id, :name, brands: %i[id name])\n  .where(brands: { name: \"Acme\" })\n  .per(10)\n  .to_a\n\n# Faceting + grouping\nrel = SearchEngine::Product\n        .facet_by(:brand_id, max_values: 5)\n        .facet_by(:category)\n        .group_by(:brand_id, limit: 3)\nparams = rel.to_h # compiled Typesense params\n\n# Multi-search\nresult_set = SearchEngine.multi_search(common: { query_by: SearchEngine.config.default_query_by }) do |m|\n  m.add :products, SearchEngine::Product.where(\"name:~rud\").per(10)\n  m.add :brands,   SearchEngine::Brand.all.per(5)\nend\nresult_set[:products].found\n\n# Upserting documents\nproduct_record = Product.first\nmapped = SearchEngine::Product.mapped_data_for(product_record)\n\n# Map + upsert a single record\nSearchEngine::Product.upsert(record: product_record)\n\n# Upsert already-mapped data\nSearchEngine::Product.upsert(data: mapped)\n\n# Bulk upsert records (mapper runs internally)\nSearchEngine::Product.upsert_bulk(records: Product.limit(2))\n\n# Bulk upsert mapped payloads\nSearchEngine::Product.upsert_bulk(data: [mapped])\n```\n\n## Documentation\n\nSee the [Docs](https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/index)\n\n## Test/offline mode\n\nIn test environments (`Rails.env.test?` or `RACK_ENV=test`), SearchEngine defaults to an offline client\n(`SearchEngine::Test::OfflineClient`) so no Typesense HTTP calls are made.\n\nYou can control this explicitly with:\n- `SEARCH_ENGINE_TEST_MODE=1` to force offline mode\n- `SEARCH_ENGINE_TEST_MODE=0` to disable offline mode\n- `SEARCH_ENGINE_OFFLINE=1` (legacy alias)\n\nIf you set `SearchEngine.configure { |c| c.client = ... }`, the custom client is always used.\n\n## Example app\n\nSee `examples/demo_shop` — demonstrates single/multi search, JOINs, grouping, presets/curation, and DX/observability. Supports offline mode via the stub client (see [Testing](https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/testing)).\n\n## Contributing\n\nSee [Docs Style Guide](https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/docs-style-guide). Follow YARDoc for public APIs, add backlinks on docs landing pages, and redact secrets in examples.\n\n\u003c!-- Badge references (placeholders) --\u003e\n[ci-badge]: https://img.shields.io/github/actions/workflow/status/lstpsche/search-engine-for-typesense/ci.yml?branch=main\n[ci-url]: #\n[gem-badge]: https://badge.fury.io/rb/search-engine-for-typesense.svg?icon=si%3Arubygems\n[gem-url]: https://rubygems.org/gems/search-engine-for-typesense\n[docs-badge]: https://img.shields.io/badge/docs-index-blue\n[docs-url]: https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/index\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flstpsche%2Fsearch-engine-for-typesense","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flstpsche%2Fsearch-engine-for-typesense","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flstpsche%2Fsearch-engine-for-typesense/lists"}