Skip to main content

Supabase source connector for moss-connectors.

Project description

moss-connector-supabase

Supabase source connector for Moss. Uses supabase-py to read rows from a Supabase table over PostgREST.

Install

pip install moss-connector-supabase

This installs supabase automatically.

Usage

import asyncio
from moss import DocumentInfo
from moss_connector_supabase import SupabaseConnector, ingest

async def main():
    source = SupabaseConnector(
        url="https://xxx.supabase.co",
        key="your-anon-or-service-key",
        table="articles",
        mapper=lambda row: DocumentInfo(
            id=str(row["id"]),
            text=row["body"],
            metadata={"title": row["title"]},
        ),
    )

    result = await ingest(
        source,
        project_id="your_project_id",
        project_key="your_project_key",
        index_name="articles",
    )
    print(f"copied {result.doc_count} rows")

asyncio.run(main())

Use auto_id=True when your mapper does not have a stable primary key and you want Moss to generate UUID document IDs.

Data requirements

The connector doesn't impose a schema — it reads each row as a dict and passes it to your mapper. The constraints come from DocumentInfo, not the connector.

DocumentInfo fields:

Field Type Required? Typical Supabase column
id str yes a primary key — int, uuid, slug, etc.
text str yes the column you want to search (body, description, content...)
metadata Optional[Dict[str, str]] no any other columns you want filterable / displayable
embedding Optional[Sequence[float]] no only if you bring your own vectors with model_id="custom"

So your table needs at least one stringifiable column to use as id and at least one text column to use as text. Everything else is optional. Examples:

Minimalid + body:

CREATE TABLE notes (id int PRIMARY KEY, body text);
mapper=lambda row: DocumentInfo(id=str(row["id"]), text=row["body"])

Rich — extra columns flow into metadata:

CREATE TABLE articles (
    id           uuid PRIMARY KEY,
    title        text,
    body         text,
    author       text,
    published_at timestamptz,
    view_count   int,
    tags         text[]
);
mapper=lambda row: DocumentInfo(
    id=row["id"],
    text=row["body"],
    metadata={
        "title": row["title"],
        "author": row["author"],
        "published_at": str(row["published_at"]),  # timestamp -> str
        "view_count": str(row["view_count"]),      # int -> str
        "tags": ",".join(row["tags"]),             # array -> joined str
    },
)

One gotcha: metadata values must be strings

Postgres types like int, bool, timestamp, numeric, array, jsonb come back from Supabase as their native Python types (int, bool, datetime, list, dict). DocumentInfo.metadata requires Dict[str, str], so non-string columns must be coerced in the mapper:

# WILL FAIL — non-string values
metadata={"price": row["price"], "in_stock": row["in_stock"]}

# CORRECT
metadata={"price": str(row["price"]), "in_stock": str(row["in_stock"])}

The same applies to id if your primary key is an int — wrap with str(...).

What you can't do (use a view instead)

  • Joins across tables — read-from-one-table only. Combine in a Postgres view (CREATE VIEW articles_with_author AS SELECT a.*, u.name AS author_name FROM articles a JOIN users u ON ...) and point the connector at the view.
  • Filter rows in Python — there's no filter= kwarg (see Filtering). Use a view to pre-filter server-side.

Choosing a key

The key argument controls which rows are visible:

  • anon key — only rows allowed by your Row-Level Security policies. Use this for ingesting publicly readable content.
  • service-role key — bypasses RLS. Use this for full-table ingest in trusted backend jobs. Never ship a service-role key to a client.

The connector does not enforce this; pick the right key for your use case.

Filtering

The connector reads every row in the named table. To restrict ingest to a subset, create a Postgres view in Supabase and point the connector at the view:

CREATE VIEW search_corpus AS
  SELECT id, title, body FROM articles WHERE published = true;
SupabaseConnector(table="search_corpus", ...)

A filter= kwarg is intentionally not exposed in v1 — Supabase's filter API is method-chained and doesn't fit a single-kwarg shape cleanly. If you need parameterized server-side filtering, open an issue.

Pagination

PostgREST is HTTP-only with no streaming cursor, so the connector pages with .range(start, end). Default page_size=1000 matches PostgREST's default db-max-rows cap. Do not raise this above your project's server-side cap — PostgREST silently truncates the response, the connector sees a short page, and stops, missing the rest of the table.

Layout

src/
├── __init__.py      # re-exports SupabaseConnector and ingest
├── connector.py     # SupabaseConnector class
└── ingest.py        # ingest() - keep in sync with the other connector packages

Tests

pip install -e ".[dev]"
pytest tests/test_supabase.py -v                          # mocked, no network needed
pytest tests/test_integration_supabase_moss.py -v -s      # live Supabase + Moss

The integration test requires SUPABASE_URL, SUPABASE_KEY, MOSS_PROJECT_ID, MOSS_PROJECT_KEY, and SUPABASE_TEST_TABLE (a pre-created table with id, title, body columns; supabase-py can't create tables over PostgREST).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

moss_connector_supabase-0.0.1.tar.gz (8.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

moss_connector_supabase-0.0.1-py3-none-any.whl (5.5 kB view details)

Uploaded Python 3

File details

Details for the file moss_connector_supabase-0.0.1.tar.gz.

File metadata

  • Download URL: moss_connector_supabase-0.0.1.tar.gz
  • Upload date:
  • Size: 8.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for moss_connector_supabase-0.0.1.tar.gz
Algorithm Hash digest
SHA256 05c32c8cb4c552440b785b7adca3c610e6d3763c20c25dc9729cb3cf5bf56b8d
MD5 6a95d64b5d3f1287e5b2ac8859f38763
BLAKE2b-256 1beee915111500856700c48eebbeeaab6ae87fc0d30dfc2cb39d08ae71e0ddba

See more details on using hashes here.

File details

Details for the file moss_connector_supabase-0.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for moss_connector_supabase-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 8c74ef3c0a205e8c62b33661fcb4d4a67f3e0cdac16a59ef12643eb8f07e7445
MD5 07525fb80d5ee46e2905e8ca4acc9da7
BLAKE2b-256 e6a70ccbf8ac9f2810e9bbea0520e88cae88886bcfc1d666aa2ac0106fd9fd60

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page