{"id":47706130,"url":"https://github.com/oceanbase/seekdb-js","last_synced_at":"2026-04-02T17:58:35.502Z","repository":{"id":333825621,"uuid":"1132479052","full_name":"oceanbase/seekdb-js","owner":"oceanbase","description":"The JavaScript/TypeScript SDK for OceanBase or OceanBase seekdb.","archived":false,"fork":false,"pushed_at":"2026-03-26T08:05:58.000Z","size":839,"stargazers_count":19,"open_issues_count":10,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-03-26T13:36:40.682Z","etag":null,"topics":["ai","javascript","sdk-js","typescript"],"latest_commit_sha":null,"homepage":"https://www.oceanbase.ai","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oceanbase.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2026-01-12T02:35:48.000Z","updated_at":"2026-03-26T07:13:03.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/oceanbase/seekdb-js","commit_stats":null,"previous_names":["oceanbase/seekdb-js"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/oceanbase/seekdb-js","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oceanbase%2Fseekdb-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oceanbase%2Fseekdb-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oceanbase%2Fseekdb-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oceanbase%2Fseekdb-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oceanbase","download_url":"https://codeload.github.com/oceanbase/seekdb-js/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oceanbase%2Fseekdb-js/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31312744,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"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":["ai","javascript","sdk-js","typescript"],"created_at":"2026-04-02T17:58:34.694Z","updated_at":"2026-04-02T17:58:35.481Z","avatar_url":"https://github.com/oceanbase.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\u003ch1\u003eseekdb-js\u003c/h1\u003e\n\n[![npm version](https://img.shields.io/npm/v/seekdb.svg)](https://www.npmjs.com/package/seekdb) [![npm downloads](https://img.shields.io/npm/dm/seekdb.svg)](https://www.npmjs.com/package/seekdb) [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/) [![Node.js](https://img.shields.io/badge/Node.js-20+-green.svg)](https://nodejs.org/) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/oceanbase/seekdb-js/pulls)\n\u003cbr /\u003e\n\n\u003cstrong\u003eVector database SDK for JavaScript/TypeScript with built-in semantic search\u003c/strong\u003e\n\u003cbr /\u003e\n\u003cem\u003eWorks seamlessly with seekdb and OceanBase\u003c/em\u003e\n\n\u003c/div\u003e\n\nFor complete usage, see the official documentation.\n\n## Table of contents\n\n[Why seekdb-js?](#why-seekdb-js)\u003cbr/\u003e\n[Packages](#packages)\u003cbr/\u003e\n[Installation](#installation)\u003cbr/\u003e\n[Running Modes](#running-modes)\u003cbr/\u003e\n[Quick Start](#quick-start)\u003cbr/\u003e\n[Usage Guide](#usage-guide)\u003cbr/\u003e\n[Examples](#examples)\u003cbr/\u003e\n[Development](#development)\u003cbr/\u003e\n[License](#license)\u003cbr/\u003e\n\n## Why seekdb-js?\n\n- **Auto Vectorization** - Automatic embedding generation, no manual vector calculation needed\n- **Semantic Search** - Vector-based similarity search for natural language queries\n- **Hybrid Search** - Combine keyword matching with semantic search\n- **Multiple Embedding Functions** - Built-in support for local and cloud embedding providers\n- **TypeScript Native** - Full TypeScript support with complete type definitions\n\n## Packages\n\nThis is a monorepo containing:\n\n| Package                  | Description                                                                 |\n| ------------------------ | --------------------------------------------------------------------------- |\n| `seekdb`                 | Core SDK for seekdb operations                                              |\n| `@seekdb/default-embed`  | Local embedding function using Xenova/all-MiniLM-L6-v2 model (default)      |\n| `@seekdb/qwen`           | DashScope/Tongyi Qianwen cloud embedding service                            |\n| `@seekdb/openai`         | OpenAI cloud embedding service                                              |\n| `@seekdb/jina`           | Jina AI multimodal embedding service                                        |\n| `@seekdb/bm25`           | BM25 sparse embedding function for efficient text-based keyword search      |\n| `@seekdb/prisma-adapter` | Prisma driver adapter for seekdb Embedded (use Prisma with seekdb Embedded) |\n\n## Installation\n\n```bash\nnpm install seekdb @seekdb/default-embed\n```\n\n- **Embedded mode**: No seekdb server deployment required; use locally after install.\n- **Server mode**: Deploy seekdb or OceanBase first; see [official deployment docs](https://www.oceanbase.ai/docs/deploy-overview/).\n\n## Running Modes\n\nThe SDK supports two modes; the constructor arguments to `SeekdbClient` determine which is used. For database management (create/list/get/delete database), use `SeekdbAdminClient()` which returns a `SeekdbClient` instance.\n\n| Mode         | Parameter                                     | Description                                                                                                                                         |\n| ------------ | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |\n| **Embedded** | `path` (database directory path)              | Runs locally with no separate seekdb server; data is stored under the given path (e.g. `./seekdb.db`). Requires native addon `@seekdb/js-bindings`. |\n| **Server**   | `host` (and `port`, `user`, `password`, etc.) | Connects to a remote seekdb or OceanBase instance.                                                                                                  |\n\n**OceanBase and seekdb**: OceanBase is compatible with seekdb and can be understood as its distributed, multi-tenant, etc. version. seekdb-js therefore supports **OceanBase server mode** with the same API: use the same `SeekdbClient` / `SeekdbAdminClient` and connection parameters; when connecting to OceanBase, additionally pass `tenant` (e.g. `\"sys\"` or your tenant name). See [OceanBase mode](#oceanbase-mode-server-mode-with-tenant) below.\n\n- **SeekdbClient**: Pass `path` for embedded mode, or `host` (and port, user, password, etc.) for server mode.\n- **SeekdbAdminClient()**: For admin operations only; pass `path` for embedded or `host` for server. In embedded mode you do not specify a database name.\n\n## Quick Start\n\n**Embedded mode** (local file, no server):\n\n```typescript\nimport { SeekdbClient } from \"seekdb\";\n\n// 1. Connect\nconst client = new SeekdbClient({\n  path: \"./seekdb.db\",\n  database: \"test\",\n});\n\n// 2. Create collection\nconst collection = await client.createCollection({ name: \"my_collection\" });\n\n// 3. Add data (auto-vectorized using @seekdb/default-embed)\nawait collection.add({\n  ids: [\"1\", \"2\"],\n  documents: [\"Hello world\", \"seekdb is fast\"],\n});\n\n// 4. Search\nconst results = await collection.query({ queryTexts: \"Hello\", nResults: 5 });\nconsole.log(\"query results\", results);\n```\n\n**Server mode** (connect to a deployed seekdb):\n\n```typescript\nimport { SeekdbClient } from \"seekdb\";\n\n// 1. Connect\nconst client = new SeekdbClient({\n  host: \"127.0.0.1\",\n  port: 2881,\n  user: \"root\",\n  password: \"\",\n  database: \"test\",\n});\n\n// 2. Create collection\nconst collection = await client.createCollection({ name: \"my_collection\" });\n\n// 3. Add data (auto-vectorized using @seekdb/default-embed)\nawait collection.add({\n  ids: [\"1\", \"2\"],\n  documents: [\"Hello world\", \"seekdb is fast\"],\n});\n\n// 4. Search\nconst results = await collection.query({ queryTexts: \"Hello\", nResults: 5 });\nconsole.log(\"query results\", results);\n```\n\n## Usage Guide\n\nThis section covers basic usage. See the [official SDK documentation](https://www.oceanbase.ai/docs/seekdb-js-get-started) for full details.\n\n### Client Connection\n\n**Embedded mode** (local database file):\n\n```typescript\nimport { SeekdbClient } from \"seekdb\";\n\nconst client = new SeekdbClient({\n  path: \"./seekdb.db\", // database file path\n  database: \"test\",\n});\n```\n\n**Server mode**:\n\n```typescript\nimport { SeekdbClient } from \"seekdb\";\n\nconst client = new SeekdbClient({\n  host: \"127.0.0.1\",\n  port: 2881,\n  user: \"root\",\n  password: \"\",\n  database: \"test\",\n});\n```\n\n**OceanBase mode** (server mode with tenant): OceanBase is compatible with seekdb (distributed, multi-tenant, etc.). Use the same server-mode connection; when the backend is OceanBase, pass `tenant` (e.g. `\"sys\"` or your tenant name):\n\n```typescript\nconst client = new SeekdbClient({\n  host: \"127.0.0.1\",\n  port: 2881,\n  user: \"root\",\n  password: \"\",\n  database: \"test\",\n  tenant: \"sys\", // or your OceanBase tenant\n});\n```\n\n### Create Collection\n\nYou can create a collection without any configuration; the default embedding function will be used for vectorization. Ensure `@seekdb/default-embed` is installed first.\n\n```typescript\nconst collection = await client.createCollection({\n  name: \"my_collection\",\n});\n```\n\n#### Schema API\n\nA schema defines which indexes are available on a collection:\n\n- **FulltextIndexConfig** - For keyword-based full-text search\n- **VectorIndexConfig** - For dense vector similarity search\n- **SparseVectorIndexConfig** - For sparse vector similarity search\n\nExamples for creating the three index types:\n\n**FulltextIndexConfig**\n\n```typescript\nconst schema = new Schema({\n  fulltextIndex: new FulltextIndexConfig(\"ik\", { ik_mode: \"smart\" }),\n});\nconst collection = await client.createCollection({\n  name: \"ft_collection\",\n  schema,\n});\n```\n\n**VectorIndexConfig**\n\nIf you do not set `embeddingFunction`, the default embedding function is used. Ensure `@seekdb/default-embed` is installed.\n\n```typescript\nconst schema = new Schema({\n  vectorIndex: new VectorIndexConfig({\n    hnsw: { dimension: 384, distance: \"cosine\" },\n  }),\n});\nconst collection = await client.createCollection({\n  name: \"vec_collection\",\n  schema,\n});\n```\n\nTo use a custom embedding function, install one of the provided packages or implement your own. See the [official SDK documentation](https://www.oceanbase.ai/docs/seekdb-js-get-started) for details.\n\nTake `@seekdb/qwen` as an example:\n\n```bash\nnpm install @seekdb/qwen\n```\n\n```typescript\nimport { QwenEmbeddingFunction } from \"@seekdb/qwen\";\n\nconst qwenEF = new QwenEmbeddingFunction();\n\nconst schema = new Schema({\n  vectorIndex: new VectorIndexConfig({\n    hnsw: { dimension: 384, distance: \"cosine\" },\n    embeddingFunction: qwenEF,\n  }),\n});\n\nconst collection = await client.createCollection({\n  name: \"my_collection\",\n  schema,\n});\n```\n\nIf you don't need an embedding function, set `embeddingFunction` to `null`.\n\n```typescript\nconst schema = new Schema({\n  vectorIndex: new VectorIndexConfig({\n    hnsw: { dimension: 384, distance: \"cosine\" },\n    embeddingFunction: null,\n  }),\n});\nconst collection = await client.createCollection({\n  name: \"vec_collection\",\n  schema,\n});\n```\n\n**SparseVectorIndexConfig**\n\nYou can use the provided `@seekdb/bm25` as the sparse embedding function or implement your own.\n\n```bash\nnpm install @seekdb/bm25\n```\n\n```typescript\nimport { Bm25EmbeddingFunction } from \"@seekdb/bm25\";\nimport { K } from \"seekdb\";\n\nconst schema = new Schema({\n  sparseVectorIndex: new SparseVectorIndexConfig({\n    sourceKey: K.DOCUMENT,\n    embeddingFunction: new Bm25EmbeddingFunction(),\n  }),\n});\n\nconst collection = await client.createCollection({\n  name: \"sparse_collection\",\n  schema,\n});\n```\n\n### Add Data\n\nThe embedding function defined in `Schema` is used automatically for vectorization. No need to set it again.\n\n```typescript\nawait collection.add({\n  ids: [\"1\", \"2\"],\n  documents: [\"Hello world\", \"seekdb is fast\"],\n  metadatas: [{ category: \"test\" }, { category: \"db\" }],\n});\n```\n\nYou can also pass a vector or an array of vectors directly.\n\n```typescript\nconst qwenEF = new QwenEmbeddingFunction();\nawait collection.add({\n  ids: [\"1\", \"2\"],\n  documents: [\"Hello world\", \"seekdb is fast\"],\n  metadatas: [{ category: \"test\" }, { category: \"db\" }],\n  embeddings: [\n    [0.1, 0.2, 0.3],\n    [0.2, 0.3, 0.4],\n  ],\n});\n```\n\n### Query Data\n\n**Get Data**\n\nThe `get() `method is used to retrieve documents from a collection without performing vector similarity search.\n\n```typescript\nconst results = await collection.get({\n  ids: [\"1\", \"2\"],\n});\n```\n\n**Semantic Search**\n\nThe `query()` method is used to execute vector similarity search to find documents most similar to the query vector.\n\nThe embedding function defined in `Schema` is used automatically for vectorization. No need to set it again.\n\n```typescript\nconst results = await collection.query({\n  queryTexts: \"Hello\",\n  nResults: 5,\n});\n```\n\nYou can also pass a vector or an array of vectors directly.\n\n```typescript\nconst results = await collection.query({\n  queryEmbeddings: [\n    [0.1, 0.2, 0.3],\n    [0.2, 0.3, 0.4],\n  ],\n  nResults: 5,\n});\n```\n\nSpecify `queryKey` to run sparse vector search. If a sparse embedding function is defined, `queryTexts` will be vectorized automatically.\n\n```typescript\nimport\nimport { K } from \"seekdb\";\n\nconst results = await collection.query({\n  queryTexts: \"artificial intelligence\",\n  // Use sparse vector index, default by K.EMBEDDING\n  queryKey: K.EMBEDDING,\n  nResults: 3,\n});\n```\n\nYou can also supply your own sparse vectors for search.\n\n```typescript\nconst queryVector: SparseVector = { 1234: 0.5, 5678: 0.8 };\n\nconst results = await collection.query({\n  queryEmbeddings: queryVector,\n  queryKey: K.SPARSE_EMBEDDING,\n  nResults: 5,\n});\n```\n\n**Hybrid Search (Keyword + Semantic)**\n\nThe `hybridSearch()` combines full-text search and vector similarity search with ranking.\n\n```typescript\nconst hybridResults = await collection.hybridSearch({\n  query: { whereDocument: { $contains: \"seekdb\" } },\n  knn: { queryTexts: [\"fast database\"] },\n  nResults: 5,\n});\n```\n\nYou can also pass a vector or an array of vectors directly.\n\n```typescript\nconst hybridResults = await collection.hybridSearch({\n  query: { whereDocument: { $contains: \"seekdb\" } },\n  knn: {\n    queryEmbeddings: [\n      [0.1, 0.2, 0.3],\n      [0.2, 0.3, 0.4],\n    ],\n  },\n  nResults: 5,\n});\n```\n\n### Embedding Functions\n\nThe SDK supports multiple Embedding Functions for generating vectors locally or in the cloud.\n\nFor complete usage, see the official documentation.\n\n#### Default Embedding\n\nUses a local model (`Xenova/all-MiniLM-L6-v2`) by default. No API Key required. Suitable for quick development and testing.\n\nNo configuration is needed to use the default model.\n\nFirst install the built-in model:\n\n```bash\nnpm install @seekdb/default-embed\n```\n\nThen use it as-is; it will auto-vectorize:\n\n```typescript\nconst collection = await client.createCollection({\n  name: \"local_embed_collection\",\n});\n```\n\n#### Qwen Embedding\n\nUses DashScope's cloud Embedding service (Qwen/Tongyi Qianwen). Suitable for production environments.\n\n```bash\nnpm install @seekdb/qwen\n```\n\n```typescript\nimport { QwenEmbeddingFunction } from \"@seekdb/qwen\";\n\nconst qwenEmbed = new QwenEmbeddingFunction({\n  // Your DashScope environment variable name, defaults to 'DASHSCOPE_API_KEY'\n  apiKeyEnvVar: 'DASHSCOPE_API_KEY'\n  // Optional, defaults to 'text-embedding-v4'\n  modelName: \"text-embedding-v4\",\n});\n\nconst collection = await client.createCollection({\n  name: \"qwen_embed_collection\",\n  embeddingFunction: qwenEmbed,\n});\n```\n\n#### OpenAI Embedding\n\nUses OpenAI's embedding API. Suitable for production environments with OpenAI integration.\n\n```bash\nnpm install @seekdb/openai\n```\n\n```typescript\nimport { OpenAIEmbeddingFunction } from \"@seekdb/openai\";\n\nconst openaiEmbed = new OpenAIEmbeddingFunction({\n  // Your openai environment variable name, defaults to 'OPENAI_API_KEY'\n  apiKeyEnvVar: 'OPENAI_API_KEY'\n  // Optional, defaults to 'text-embedding-3-small'\n  modelName: \"text-embedding-3-small\",\n});\n\nconst collection = await client.createCollection({\n  name: \"openai_embed_collection\",\n  embeddingFunction: openaiEmbed,\n});\n```\n\n#### Jina Embedding\n\nUses Jina AI's embedding API. Supports multimodal embeddings.\n\n```bash\nnpm install @seekdb/jina\n```\n\n```typescript\nimport { JinaEmbeddingFunction } from \"@seekdb/jina\";\n\nconst jinaEmbed = new JinaEmbeddingFunction({\n  // Your jina environment variable name, defaults to 'JINA_API_KEY'\n  apiKeyEnvVar: 'JINA_API_KEY'\n  // Optional, defaults to jina-clip-v2\n  modelName: \"jina-clip-v2\",\n});\n\nconst collection = await client.createCollection({\n  name: \"jina_embed_collection\",\n  embeddingFunction: jinaEmbed,\n});\n```\n\n#### Custom Embedding Function\n\nYou can also use your own custom embedding function.\n\nFirst, implement the `EmbeddingFunction` interface:\n\n```typescript\nimport type { EmbeddingFunction } from \"seekdb\";\nimport { registerEmbeddingFunction } from \"seekdb\";\n\ninterface MyCustomEmbeddingConfig {\n  apiKeyEnv: string;\n}\nclass MyCustomEmbeddingFunction implements EmbeddingFunction {\n  // The name of the `embeddingFunction`, must be unique.\n  readonly name = \"my_custom_embedding\";\n  private apiKeyEnv: string;\n  dimension: number;\n  constructor(config: MyCustomEmbeddingConfig) {\n    this.apiKeyEnv = config.apiKeyEnv;\n    this.dimension = 384;\n  }\n  // Implement your vector generation code here\n  async generate(texts: string[]): Promise\u003cnumber[][]\u003e {\n    const embeddings: number[][] = [];\n    return embeddings;\n  }\n  // The configuration of the current `embeddingFunction` instance, used to restore this instance\n  getConfig(): MyCustomEmbeddingConfig {\n    return {\n      apiKeyEnv: this.apiKeyEnv,\n    };\n  }\n  // Create a new instance of the current `embeddingFunction` based on the provided configuration\n  static buildFromConfig(config: MyCustomEmbeddingConfig): EmbeddingFunction {\n    return new MyCustomEmbeddingFunction(config);\n  }\n}\n\n// Register the constructor\nregisterEmbeddingFunction(\"my_custom_embedding\", MyCustomEmbeddingFunction);\n```\n\nThen use it:\n\n```typescript\nconst customEmbed = new MyCustomEmbeddingFunction({\n  apiKeyEnv: \"MY_CUSTOM_API_KEY_ENV\",\n});\nconst collection = await client.createCollection({\n  name: \"custom_embed_collection\",\n  configuration: {\n    dimension: 384,\n    distance: \"cosine\",\n  },\n  embeddingFunction: customEmbed,\n});\n```\n\n### BM25 Sparse Embedding\n\nBM25 (Best Matching 25) is a sparse embedding function that uses term frequency and document length normalization for efficient text search. It's particularly useful for keyword-based search scenarios.\n\n```bash\nnpm install @seekdb/bm25\n```\n\n```typescript\nimport { SeekdbClient, Schema, SparseVectorIndexConfig, K } from \"seekdb\";\nimport { Bm25EmbeddingFunction } from \"@seekdb/bm25\";\n\nconst bm25 = new Bm25EmbeddingFunction({\n  k: 1.2, // Term frequency saturation\n  b: 0.75, // Document length normalization\n  avgDocLength: 256, // Average document length\n  tokenMaxLength: 40, // Maximum token length\n  stopwords: [\"a\", \"an\", \"the\"], // Custom stopwords\n});\n\nconst collection = await client.createCollection({\n  name: \"bm25_collection\",\n  schema: new Schema({\n    sparseVectorIndex: new SparseVectorIndexConfig({\n      sourceKey: K.DOCUMENT,\n      embeddingFunction: bm25,\n    }),\n  }),\n});\n```\n\nFor more details, see [BM25 Embedding Guide](./docs/bm25-embedding-guide.md).\n\n#### Custom Sparse Embedding Function\n\nImplement your own sparse embedding function:\n\n```typescript\nimport {\n  SparseEmbeddingFunction,\n  SparseVector,\n  registerSparseEmbeddingFunction,\n  EmbeddingConfig,\n} from \"seekdb\";\n\ninterface MySparseConfig {\n  vocabSize: number;\n}\n\nclass MySparseEmbeddingFunction implements SparseEmbeddingFunction {\n  readonly name = \"my_sparse\";\n  private vocabSize: number;\n\n  constructor(config: MySparseConfig) {\n    this.vocabSize = config.vocabSize;\n  }\n\n  // Implement your vector generation code here\n  async generate(texts: string[]): Promise\u003cSparseVector[]\u003e {\n    const embeddings: number[][] = [];\n    return embeddings;\n  }\n\n  // Generate sparse vectors for queries (can be different)\n  async generateForQueries(texts: string[]): Promise\u003cSparseVector[]\u003e {\n    return this.generate(texts);\n  }\n\n  // Return configuration for persistence\n  getConfig(): EmbeddingConfig {\n    return { vocabSize: this.vocabSize };\n  }\n\n  // Static factory method\n  static buildFromConfig(config: EmbeddingConfig): SparseEmbeddingFunction {\n    return new MySparseEmbeddingFunction(config as MySparseConfig);\n  }\n}\n\n// Register the function\nregisterSparseEmbeddingFunction(\"my_sparse\", MySparseEmbeddingFunction);\n\n// Use it\nconst collection = await client.createCollection({\n  name: \"my_sparse_collection\",\n  schema: {\n    sparseVectorIndex: new SparseVectorIndexConfig({\n      sourceKey: K.DOCUMENT,\n      embeddingFunction: new MySparseEmbeddingFunction({ vocabSize: 100000 }),\n    }),\n  },\n});\n```\n\n### Vector search + relational tables\n\nYou can combine vector (or hybrid) search with relational tables: run `collection.query()` or `collection.hybridSearch()` to get `ids`, then query your relational table by those ids. For type-safe relational queries, prefer an ORM (see [Integration with ORM](#integration-with-orm)); here is a raw-SQL recipe.\n\n**Recipe**\n\n1. Get ids (and optional metadata) from vector/hybrid search.\n2. Query the relational table with `client.execute()`. For `WHERE id IN (...)` with MySQL/mysql2, use parameterized placeholders to avoid SQL injection: one `?` per id and pass the ids array as params.\n\n**Example (TypeScript)** — hybrid search, then fetch users by id and merge:\n\n```typescript\nconst client = new SeekdbClient({\n  host: \"127.0.0.1\",\n  port: 2881,\n  user: \"root\",\n  password: \"\",\n  database: \"test\",\n});\nconst collection = await client.getCollection({ name: \"my_collection\" });\n\n// 1. Hybrid search → get ids\nconst hybridResult = await collection.hybridSearch({\n  query: { whereDocument: { $contains: \"seekdb\" } },\n  knn: { queryTexts: [\"fast database\"] },\n  nResults: 5,\n});\nconst ids = hybridResult.ids?.flat().filter(Boolean) ?? []; // e.g. string[]\n\n// 2. Query relational table by ids (parameterized)\ntype UserRow = { id: string; name: string };\nlet users: UserRow[] = [];\nif (ids.length \u003e 0) {\n  const placeholders = ids.map(() =\u003e \"?\").join(\",\");\n  const rows = await client.execute(\n    `SELECT id, name FROM users WHERE id IN (${placeholders})`,\n    ids\n  );\n  users = (rows ?? []) as UserRow[];\n}\n\n// 3. Merge: e.g. map ids to (vector result + user row)\nconst merged = ids.map((id) =\u003e ({\n  id,\n  user: users.find((u) =\u003e u.id === id) ?? null,\n}));\n```\n\n**Transactions**: There is no explicit transaction API on the client. For transactions that span both vector and relational operations, use a separate mysql2 connection (same DB config) and run `beginTransaction()` / `commit()` / `rollback()` on that connection (see [Integration with ORM](#integration-with-orm)).\n\n### Integration with ORM\n\nUse seekdb-js for vector/full-text/hybrid search and an ORM (Drizzle or Prisma) for type-safe relational tables. seekdb is MySQL-compatible in both modes. **Server mode**: same database, two connections (SeekdbClient + ORM). **Embedded mode**: Drizzle uses `drizzle-orm/mysql-proxy` with a callback around `client.execute()`; Prisma uses [@seekdb/prisma-adapter](https://www.npmjs.com/package/@seekdb/prisma-adapter).\n\n#### Drizzle\n\n**Server mode**: Create a mysql2 connection with the same DB config as SeekdbClient and pass it to `drizzle(conn)`.\n\n```typescript\nimport { createConnection } from \"mysql2/promise\";\nimport { SeekdbClient } from \"seekdb\";\nimport { drizzle } from \"drizzle-orm/mysql2\";\nimport { inArray } from \"drizzle-orm\";\nimport { users } from \"./schema\"; // mysqlTable, relational only; vector tables via Collection\n\nconst dbConfig = {\n  host: \"127.0.0.1\",\n  port: 2881,\n  user: \"root\",\n  password: \"\",\n  database: \"test\",\n};\nconst client = new SeekdbClient(dbConfig);\nconst conn = await createConnection(dbConfig);\nconst db = drizzle(conn);\n\nconst collection = await client.getCollection({ name: \"docs\" });\nconst result = await collection.hybridSearch({\n  query: { whereDocument: { $contains: \"seekdb\" } },\n  knn: { queryTexts: [\"database\"] },\n  nResults: 5,\n});\nconst ids = result.ids?.flat().filter(Boolean) ?? [];\nconst usersList = await db.select().from(users).where(inArray(users.id, ids));\n// when done: await conn.end(); await client.close();\n```\n\n**Embedded mode**: Use `drizzle-orm/mysql-proxy` with a callback that runs SQL via `client.execute()` and returns `{ rows }`. See [seekdb-drizzle](./examples/seekdb-drizzle/index-embedded.ts) for a runnable sample.\n\n#### Prisma\n\n**Server mode**: Use SeekdbClient and PrismaClient with `DATABASE_URL` pointing to the same database.\n\n```typescript\nimport { SeekdbClient } from \"seekdb\";\nimport { PrismaClient } from \"@prisma/client\";\n\nconst client = new SeekdbClient({\n  host: \"127.0.0.1\",\n  port: 2881,\n  user: \"root\",\n  password: \"\",\n  database: \"test\",\n});\nconst prisma = new PrismaClient(); // DATABASE_URL=\"mysql://root:@127.0.0.1:2881/test\"\n\nconst collection = await client.getCollection({ name: \"docs\" });\nconst result = await collection.hybridSearch({\n  query: { whereDocument: { $contains: \"seekdb\" } },\n  knn: { queryTexts: [\"database\"] },\n  nResults: 5,\n});\nconst ids = result.ids?.flat().filter(Boolean) ?? [];\nconst users = await prisma.user.findMany({ where: { id: { in: ids } } });\n// merge as needed; when done: await client.close(); await prisma.$disconnect();\n```\n\nSet `DATABASE_URL` to the same host/port/user/password/database (e.g. `mysql://user:password@host:port/database`). OceanBase: see Prisma/MySQL tenant docs.\n\n**Embedded mode**: Use [@seekdb/prisma-adapter](https://www.npmjs.com/package/@seekdb/prisma-adapter) with `PrismaClient({ adapter })` so Prisma runs SQL via `client.execute()`. See [seekdb-prisma](./examples/seekdb-prisma/index-embedded.ts); run `pnpm run start:embedded` in that example.\n\n### Database Management\n\nUse `SeekdbAdminClient` for database management. It supports both embedded and server modes.\n\n**Embedded mode** (local database file):\n\n```typescript\nimport { SeekdbAdminClient } from \"seekdb\";\n\nconst admin = new SeekdbAdminClient({ path: \"./seekdb.db\" });\nawait admin.createDatabase(\"new_database\");\nconst databases = await admin.listDatabases();\nconst db = await admin.getDatabase(\"new_database\");\nawait admin.deleteDatabase(\"new_database\");\nawait admin.close();\n```\n\n**Server mode**:\n\n```typescript\nimport { SeekdbAdminClient } from \"seekdb\";\n\nconst admin = new SeekdbAdminClient({\n  host: \"127.0.0.1\",\n  port: 2881,\n  user: \"root\",\n  password: \"\",\n});\n\nawait admin.createDatabase(\"new_database\");\nconst databases = await admin.listDatabases();\nconst db = await admin.getDatabase(\"new_database\");\nawait admin.deleteDatabase(\"new_database\");\nawait admin.close();\n```\n\n**OceanBase mode** (server mode with tenant): add `tenant` (e.g. `\"sys\"` or your tenant name) to the config:\n\n```typescript\nconst admin = new SeekdbAdminClient({\n  host: \"127.0.0.1\",\n  port: 2881,\n  user: \"root\",\n  password: \"\",\n  tenant: \"sys\", // or your OceanBase tenant\n});\n\nawait admin.createDatabase(\"new_database\");\nconst databases = await admin.listDatabases();\nconst db = await admin.getDatabase(\"new_database\");\nawait admin.deleteDatabase(\"new_database\");\nawait admin.close();\n```\n\n`AdminClient()` is available as a factory and returns a `SeekdbClient` configured for admin operations.\n\n## Examples\n\nCheck out the [examples](./examples) directory for complete usage examples:\n\n**Basic examples** (root `examples/`):\n\n- [simple-example.ts](./examples/simple-example.ts) - Basic usage\n- [complete-example.ts](./examples/complete-example.ts) - All features\n- [hybrid-search-example.ts](./examples/hybrid-search-example.ts) - Hybrid search\n\n**ORM integration** (vector + relational tables):\n\n- [seekdb-drizzle](./examples/seekdb-drizzle) - Drizzle ORM (Server: same DB two connections; Embedded: mysql-proxy)\n- [seekdb-prisma](./examples/seekdb-prisma) - Prisma ORM (Server: DATABASE_URL; Embedded: [@seekdb/prisma-adapter](https://www.npmjs.com/package/@seekdb/prisma-adapter))\n\nTo run the examples, see [Run Examples](./DEVELOP.md#run-examples) in the development guide.\n\n## Development\n\nSee [DEVELOP.md](./DEVELOP.md) for details on development, testing, and contributing.\n\n## License\n\nThis package is licensed under [Apache 2.0](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foceanbase%2Fseekdb-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foceanbase%2Fseekdb-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foceanbase%2Fseekdb-js/lists"}