@medusajs/search-postgres 2.22.0-snapshot-20261021091347 → 2.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +57 -0
- package/README.md +107 -140
- package/package.json +8 -4
package/AGENTS.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# @medusajs/search-postgres
|
|
2
|
+
|
|
3
|
+
Search Module provider that stores and queries search indexes in the application's PostgreSQL database. Two engines: `native` (GIN + `ts_rank` + `pg_trgm`, any Postgres) and `lakebase` (BM25 + ANN vectors, Medusa Cloud only). Registered by default by `defineConfig`.
|
|
4
|
+
|
|
5
|
+
## Using this package
|
|
6
|
+
|
|
7
|
+
Registered automatically with `id: "postgres"` and `engine: "lakebase"` on Medusa Cloud, `"native"` elsewhere. Register explicitly to change options:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
module.exports = defineConfig({
|
|
11
|
+
modules: [
|
|
12
|
+
{
|
|
13
|
+
resolve: "@medusajs/medusa/search",
|
|
14
|
+
options: {
|
|
15
|
+
providers: [
|
|
16
|
+
{
|
|
17
|
+
resolve: "@medusajs/medusa/search-postgres",
|
|
18
|
+
id: "search-postgres",
|
|
19
|
+
options: {
|
|
20
|
+
// requires a medusa_search_german text search configuration
|
|
21
|
+
language: "german",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- Options (`PostgresSearchProviderOptions`): `engine` (`"native"` default | `"lakebase"`), `language` (default `"english"`), `embedder` (`(text) => Promise<number[]>`, lakebase only, needed for `.embed()` fields and `search_options.vector.query`), `vector_distance` (`"cosine"` default | `"l2"` | `"inner_product"`).
|
|
32
|
+
- After registering: `npx medusa db:migrate` (extensions + catalog table), then `npx medusa db:migrate-search` to build indexes from your index definitions.
|
|
33
|
+
- Index definitions and queries go through the Search Module / Query (`query.search(...)`), not this provider.
|
|
34
|
+
- Docs: https://docs.medusajs.com/resources/infrastructure-modules/search/providers/postgres.md
|
|
35
|
+
- Build a custom search provider: https://docs.medusajs.com/resources/references/search/provider.md
|
|
36
|
+
- Feature matrix, vector fields, filter semantics: `README.md` in this package.
|
|
37
|
+
|
|
38
|
+
## Architecture
|
|
39
|
+
|
|
40
|
+
- `src/services/postgres-search.ts`: `PostgresSearchService extends AbstractSearchProviderService` (from `@medusajs/framework/utils`), `static identifier = "search-postgres"`. Implements `upsertIndex`, `deleteIndex`, `listIndexes`, `upsertDocuments` (chunks of 200), `deleteDocuments`, `clearIndex`, `search`, `searchMany`.
|
|
41
|
+
- Uses the injected `manager` with raw SQL only (no MikroORM entities; `mikro-orm.config.dev.ts` has `entities: []`).
|
|
42
|
+
- `src/utils/plan.ts`: turns an index definition into an `IndexPlan` (one table per index, columns, GIN/BM25/ANN indexes); the catalog table `search_postgres_index` stores each plan and its `schema_hash`.
|
|
43
|
+
- `src/utils/filters.ts` (filters to SQL, jsonb containment for equality/`$in`), `facets.ts`, `documents.ts`, `extensions.ts`.
|
|
44
|
+
- `src/migrations/`: enables `pg_trgm`, `unaccent`, creates `medusa_search_english` and the catalog table. Extension creation soft-fails (`RAISE NOTICE`) when the DB role lacks privileges.
|
|
45
|
+
|
|
46
|
+
## Development
|
|
47
|
+
|
|
48
|
+
- `yarn build`, `yarn test` (unit specs in `src/utils/__tests__`).
|
|
49
|
+
- `yarn test:integration`: `integration-tests/__tests__/postgres-search.spec.ts` via `moduleIntegrationTestRunner`, needs a local Postgres with `pg_trgm`/`unaccent` available.
|
|
50
|
+
|
|
51
|
+
## Gotchas
|
|
52
|
+
|
|
53
|
+
- Providers are keyed by `identifier`, not `id`: index definitions and `default_provider` reference `search-postgres`, and registering this provider twice throws.
|
|
54
|
+
- `language` must match `/^[a-z0-9_]+$/i`, and the provider always queries the `medusa_search_<language>` text search config. Only `medusa_search_english` is created by the migration; create others yourself.
|
|
55
|
+
- Native engine: vector fields in a definition are dropped with a warning, but queries with `search_options.vector` are rejected.
|
|
56
|
+
- Unsupported on both engines (rejected explicitly): highlighting, geo, cursor pagination, query-time locales.
|
|
57
|
+
- Range operators, `$prefix`, and `$like` are rejected on array fields; a bare value on an array field means membership.
|
package/README.md
CHANGED
|
@@ -1,156 +1,123 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://www.medusajs.com">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/59018053/229103275-b5e482bb-4601-46e6-8142-244f531cebdb.svg">
|
|
5
|
+
<source media="(prefers-color-scheme: light)" srcset="https://user-images.githubusercontent.com/59018053/229103726-e5b529a3-9b3f-4970-8a1f-c6af37f087bf.svg">
|
|
6
|
+
<img alt="Medusa logo" src="https://user-images.githubusercontent.com/59018053/229103726-e5b529a3-9b3f-4970-8a1f-c6af37f087bf.svg">
|
|
7
|
+
</picture>
|
|
8
|
+
</a>
|
|
9
|
+
</p>
|
|
10
|
+
<h1 align="center">
|
|
11
|
+
@medusajs/search-postgres
|
|
12
|
+
</h1>
|
|
13
|
+
|
|
14
|
+
<h4 align="center">
|
|
15
|
+
<a href="https://docs.medusajs.com">Documentation</a> |
|
|
16
|
+
<a href="https://www.medusajs.com">Website</a>
|
|
17
|
+
</h4>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
Building blocks for digital commerce
|
|
21
|
+
</p>
|
|
22
|
+
<p align="center">
|
|
23
|
+
<a href="https://github.com/medusajs/medusa/blob/develop/LICENSE">
|
|
24
|
+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="Medusa is released under the MIT license." />
|
|
25
|
+
</a>
|
|
26
|
+
<a href="https://github.com/medusajs/medusa/blob/develop/CONTRIBUTING.md">
|
|
27
|
+
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" alt="PRs welcome!" />
|
|
28
|
+
</a>
|
|
29
|
+
<a href="https://discord.gg/xpCwq3Kfn8">
|
|
30
|
+
<img src="https://img.shields.io/badge/chat-on%20discord-7289DA.svg" alt="Discord Chat" />
|
|
31
|
+
</a>
|
|
32
|
+
<a href="https://twitter.com/intent/follow?screen_name=medusajs">
|
|
33
|
+
<img src="https://img.shields.io/twitter/follow/medusajs.svg?label=Follow%20@medusajs" alt="Follow @medusajs" />
|
|
34
|
+
</a>
|
|
35
|
+
</p>
|
|
36
|
+
|
|
37
|
+
PostgreSQL Search Module Provider for Medusa: full-text search, typo tolerance, filters, and facets over your search indexes, stored in the application's own PostgreSQL database. It's the default search provider, so search works without an external search engine. It ships with `@medusajs/medusa` and is registered through the `@medusajs/medusa/search-postgres` path.
|
|
38
|
+
|
|
39
|
+
## At a glance
|
|
40
|
+
|
|
41
|
+
| | |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| Package | `@medusajs/search-postgres` |
|
|
44
|
+
| Type | Module Provider (Search Module) |
|
|
45
|
+
| Provider ID | `search-postgres` |
|
|
46
|
+
| Registered by default | Yes, with `id: "postgres"` (`engine: "native"` when self-hosted, `"lakebase"` on Medusa Cloud) |
|
|
47
|
+
| Import from | `@medusajs/medusa/search-postgres` |
|
|
48
|
+
|
|
49
|
+
## Engines
|
|
50
|
+
|
|
51
|
+
| Engine | Where | Keyword search | Vector search |
|
|
52
|
+
| --- | --- | --- | --- |
|
|
53
|
+
| `native` (default) | Any PostgreSQL database | PostgreSQL full-text search (`tsvector`) with `pg_trgm` typo tolerance | Not supported |
|
|
54
|
+
| `lakebase` | Medusa Cloud only | BM25 (`lakebase_bm25`) with `pg_trgm` typo tolerance | ANN (`lakebase_ann`), and hybrid keyword + vector search |
|
|
55
|
+
|
|
56
|
+
## Features
|
|
57
|
+
|
|
58
|
+
- Free-text search with field weights and `match_strategy` `"all"` (default), `"any"`, or `"last"` (typeahead: the last term matches as a prefix).
|
|
59
|
+
- Filters with `$eq`, `$ne`, `$in`, `$nin`, range operators, and `$and` / `$or` / `$not`. On array fields, a bare value or `$eq` means "contains".
|
|
60
|
+
- Value, range, and stats facets scoped to the query's matches.
|
|
61
|
+
- `distinct` (one hit per value) and `min_score`.
|
|
62
|
+
- Vector and hybrid search on the `lakebase` engine. On `native`, vector fields are dropped from the index with a warning, and vector queries are rejected.
|
|
63
|
+
|
|
64
|
+
Highlighting, geo fields, cursor pagination, and query-time locales aren't supported and are rejected.
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
No installation needed. The provider is a dependency of `@medusajs/medusa` and is registered by default.
|
|
69
|
+
|
|
70
|
+
## Usage
|
|
71
|
+
|
|
72
|
+
Register the provider yourself to pass options:
|
|
35
73
|
|
|
36
74
|
```ts
|
|
37
|
-
{
|
|
38
|
-
resolve: "@medusajs/medusa/search-postgres",
|
|
39
|
-
id: "postgres",
|
|
40
|
-
options: {
|
|
41
|
-
engine: "lakebase",
|
|
42
|
-
// Optional: embed text for search_options.vector.query
|
|
43
|
-
// embedder: async (text) => { ... return number[] },
|
|
44
|
-
// vector_distance: "cosine", // or "l2" | "inner_product"
|
|
45
|
-
},
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Then:
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
npx medusa db:migrate
|
|
53
|
-
npx medusa db:migrate-search
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
The migration enables `pg_trgm` + `unaccent` and creates the catalog. On Medusa Cloud it also enables `lakebase_vector` and `lakebase_text` (`CREATE EXTENSION ... CASCADE`). Those statements soft-fail on engines that do not ship Lakebase Search.
|
|
57
|
-
|
|
58
|
-
## Provider options
|
|
59
|
-
|
|
60
|
-
| Option | Default | Description |
|
|
61
|
-
| ----------------- | ----------- | -------------------------------------------------------------------------------------- |
|
|
62
|
-
| `engine` | `"native"` | `"native"` or `"lakebase"` |
|
|
63
|
-
| `language` | `"english"` | Text search config. With `unaccent`, creates `medusa_search_<language>`. |
|
|
64
|
-
| `embedder` | — | `(text) => Promise<number[]>`. Required for `search_options.vector.query` on lakebase. |
|
|
65
|
-
| `vector_distance` | `"cosine"` | ANN metric: `cosine`, `l2`, or `inner_product`. |
|
|
66
|
-
|
|
67
|
-
## Vector fields (lakebase only)
|
|
75
|
+
import { defineConfig } from "@medusajs/framework/utils"
|
|
68
76
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
Supply embeddings yourself:
|
|
72
|
-
|
|
73
|
-
```ts
|
|
74
|
-
defineSearchIndex({
|
|
75
|
-
name: "product",
|
|
76
|
-
entity: "product",
|
|
77
|
-
fields: search.define({
|
|
78
|
-
id: search.keyword().filterable(),
|
|
79
|
-
title: search.text().searchable({ weight: 3 }),
|
|
80
|
-
embedding: search.vector(1536),
|
|
81
|
-
}),
|
|
77
|
+
module.exports = defineConfig({
|
|
82
78
|
// ...
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
vector: {
|
|
99
|
-
field: "embedding",
|
|
100
|
-
query: "red shoes",
|
|
101
|
-
semantic_ratio: 0.5, // 0 = keyword, 1 = vector, in between = RRF hybrid
|
|
79
|
+
modules: [
|
|
80
|
+
{
|
|
81
|
+
resolve: "@medusajs/medusa/search",
|
|
82
|
+
options: {
|
|
83
|
+
providers: [
|
|
84
|
+
{
|
|
85
|
+
resolve: "@medusajs/medusa/search-postgres",
|
|
86
|
+
id: "postgres",
|
|
87
|
+
options: {
|
|
88
|
+
// requires a medusa_search_german text search configuration
|
|
89
|
+
language: "german",
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
102
94
|
},
|
|
103
|
-
|
|
95
|
+
],
|
|
104
96
|
})
|
|
105
97
|
```
|
|
106
98
|
|
|
107
|
-
|
|
99
|
+
Then run the migrations, which enable the `pg_trgm` and `unaccent` extensions, create the `medusa_search_english` text search configuration, and create your search indexes:
|
|
108
100
|
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
entity: "product",
|
|
112
|
-
filters: { q: "red shoes" },
|
|
113
|
-
search_options: {
|
|
114
|
-
vector: {
|
|
115
|
-
field: "embedding",
|
|
116
|
-
value: embeddingArray,
|
|
117
|
-
semantic_ratio: 0.5,
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
})
|
|
101
|
+
```bash
|
|
102
|
+
npx medusa db:migrate
|
|
121
103
|
```
|
|
122
104
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
| | native | lakebase |
|
|
126
|
-
| ---------------- | ------------------------------------------------------- | ------------------------ |
|
|
127
|
-
| Free text | `ts_rank` + weights | BM25 via `lakebase_bm25` |
|
|
128
|
-
| Typo tolerance | `pg_trgm` (`word_similarity`) | `pg_trgm` (same) |
|
|
129
|
-
| `match_strategy` | `"all"` (default), `"any"`, `"last"` | same |
|
|
130
|
-
| Filters | `$eq` `$ne` `$in` `$nin` ranges, `$and`/`$or`/`$not`, … | same |
|
|
131
|
-
| Facets | value, range, stats — scoped to the query matches | same |
|
|
132
|
-
| `distinct` | one hit per value, count follows | same |
|
|
133
|
-
| `min_score` | yes, keeps the requested sort | same |
|
|
134
|
-
| Vector / hybrid | fields ignored, queries rejected | ANN + RRF |
|
|
135
|
-
|
|
136
|
-
Unsupported on both (rejected explicitly): highlighting, geo, cursor pagination, query-time locales.
|
|
105
|
+
To create or update only the search indexes, run `npx medusa db:migrate:search`.
|
|
137
106
|
|
|
138
|
-
|
|
107
|
+
If you set `language` to anything other than `english`, create a matching `medusa_search_<language>` text search configuration yourself.
|
|
139
108
|
|
|
140
|
-
|
|
109
|
+
## Configuration
|
|
141
110
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
fields.
|
|
111
|
+
| Option | Type | Description | Default |
|
|
112
|
+
| --- | --- | --- | --- |
|
|
113
|
+
| `engine` | `"native" \| "lakebase"` | The search backend. `lakebase` works only on Medusa Cloud. | `"native"` |
|
|
114
|
+
| `language` | `string` | The PostgreSQL text search configuration language, such as `english` or `simple`. | `"english"` |
|
|
115
|
+
| `embedder` | `(text: string) => Promise<number[]>` | Turns text into an embedding. Required for vector fields that use `.embed()` and for `search_options.vector.query`. | - |
|
|
116
|
+
| `vector_distance` | `"cosine" \| "l2" \| "inner_product"` | Distance metric for vector indexes. | `"cosine"` |
|
|
149
117
|
|
|
150
|
-
|
|
118
|
+
## Resources
|
|
151
119
|
|
|
152
|
-
-
|
|
153
|
-
-
|
|
154
|
-
|
|
155
|
-
-
|
|
156
|
-
the fused hit list itself is a bounded candidate window.
|
|
120
|
+
- [PostgreSQL Search Module Provider](https://docs.medusajs.com/resources/infrastructure-modules/search/providers/postgres)
|
|
121
|
+
- [Search Module](https://docs.medusajs.com/resources/infrastructure-modules/search)
|
|
122
|
+
- [Search Index Definitions](https://docs.medusajs.com/resources/infrastructure-modules/search/index-definitions)
|
|
123
|
+
- [Search with Query](https://docs.medusajs.com/learn/fundamentals/query/search)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@medusajs/search-postgres",
|
|
3
|
-
"version": "2.22.0
|
|
3
|
+
"version": "2.22.0",
|
|
4
4
|
"description": "PostgreSQL search provider for Medusa, backed by tsvector and pg_trgm",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -17,10 +17,14 @@
|
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"dist",
|
|
20
|
+
"AGENTS.md",
|
|
20
21
|
"!dist/**/__tests__",
|
|
21
22
|
"!dist/**/__mocks__",
|
|
22
23
|
"!dist/**/__fixtures__"
|
|
23
24
|
],
|
|
25
|
+
"llms": "https://docs.medusajs.com/llms.txt",
|
|
26
|
+
"llmsFull": "https://docs.medusajs.com/llms-full.txt",
|
|
27
|
+
"mcpServer": "https://docs.medusajs.com/mcp",
|
|
24
28
|
"engines": {
|
|
25
29
|
"node": ">=22.22.0"
|
|
26
30
|
},
|
|
@@ -37,11 +41,11 @@
|
|
|
37
41
|
"orm:cache:clear": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts MIKRO_ORM_ALLOW_GLOBAL_CLI=true medusa-mikro-orm cache:clear"
|
|
38
42
|
},
|
|
39
43
|
"devDependencies": {
|
|
40
|
-
"@medusajs/framework": "2.22.0
|
|
41
|
-
"@medusajs/test-utils": "2.22.0
|
|
44
|
+
"@medusajs/framework": "2.22.0",
|
|
45
|
+
"@medusajs/test-utils": "2.22.0"
|
|
42
46
|
},
|
|
43
47
|
"peerDependencies": {
|
|
44
|
-
"@medusajs/framework": "2.22.0
|
|
48
|
+
"@medusajs/framework": "2.22.0"
|
|
45
49
|
},
|
|
46
50
|
"keywords": [
|
|
47
51
|
"medusa-plugin",
|