mirror of
https://github.com/supabase/supabase.git
synced 2026-09-22 13:37:53 +08:00
29493e02d0
For Multigres (HA) projects you can't connect to read replicas directly — reads go through a read-only load balancer on the primary's host at port 5433. Since #44695 stripped the pooler UI, HA projects showed no source option at all in the Connect dialog and still prompted for the IPv4 add-on. This surfaces it as a first-class, clearly-labeled read-only source. In the UI it's labeled `Replica (read-only)` rather than "load balancer" — the primary goes through the same gateway, so "load balancer" would be confusing from a product perspective (internally the `load-balancer` source identifier and `HIGH_AVAILABILITY_LOAD_BALANCER_PORT` constant keep their names). <img width="883" height="342" alt="Screenshot 2026-08-24 at 11 32 26 PM" src="https://github.com/user-attachments/assets/3716f6dd-0325-4b9d-adbc-9ece9244de62" /> **Added:** - Source select for HA projects in the Direct tab: `Primary database` + `Replica (read-only)` (individual replica rows are filtered out — they're only reachable via the load balancer) - Replica (load balancer) connection strings on all 9 connection types: primary host, port `5433`, with the Multigres-required `sslmode=require&sslnegotiation=direct` params (JDBC gets the `sslNegotiation` spelling, .NET gets `SSL Negotiation=Direct`) - `Read-only` badge on the connection code block + note pointing writes at the primary - Programmatic labels for the ConnectSheet select/switch/multi-select fields (the Source combobox previously had no accessible name) **Changed:** - The generated-file step (Node.js/Golang/.NET/Python/SQLAlchemy) is now source-aware — it previously ignored the Source selection entirely (also affected read replicas on normal projects) and silently rendered the primary's connection info - .NET template now emits `Port=` (Npgsql defaults to 5432 when omitted) and the install step actually installs Npgsql (pinned 9.0.5 — `SSL Negotiation` requires 9+) - SQLAlchemy `DATABASE_URL` merges `sslmode=require` into the string's existing query params instead of a hardcoded suffix that could drop TLS - Source option labels normalized to sentence case (`Primary database`, `Read replica (…)`) - `MultipleCodeBlock` (ui-patterns) accepts an optional `className` - HA coercion in `useConnectState` extended: a stale replica `connectionSource` restored from URL/localStorage falls back to the primary **Removed:** - IPv4 add-on admonition for HA projects (the forced-direct method was tripping it; the add-on doesn't apply to Multigres) Out of scope (needs platform work): SQL editor / Data API / other `DatabaseSelector` surfaces — executing against the load balancer requires a platform-issued connection string, and the load-balancers API only returns a REST endpoint today. The `5433` port is a client-side constant (`HIGH_AVAILABILITY_LOAD_BALANCER_PORT`) until the API exposes it. ## To test On an HA (Multigres) project: - Open Connect → Direct: Source shows exactly `Primary database` and `Replica (read-only)`; selecting the replica shows `…@<primary-host>:5433/postgres?sslmode=require&sslnegotiation=direct`, a `Read-only` badge, and the read-only note - Cycle all 9 connection types with the replica selected — every snippet carries port 5433 (`.NET` includes `Port=5433;…;SSL Negotiation=Direct`), badge/note persist - No "Enable IPv4 add-on" admonition anywhere in the Direct tab - Switch tabs / hard-reload: source resets to primary with no stale badge/string combos On a normal project: - Direct tab unchanged: no `Replica (read-only)` option, pooler badges and IPv4 admonitions behave as before, `.NET` now shows `Port=5432` and no `SSL Negotiation` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added read-only load-balancer connection options for high-availability projects. - Added .NET and SQLAlchemy connection examples with required SSL settings. - Added clear read-only labels and notices explaining write restrictions. - **Bug Fixes** - Suppressed IPv4 add-on notices for high-availability connections. - Improved connection-source selection and restored-setting handling. - Improved connection form identification and accessibility. - **Style** - Added customizable styling support for multi-code-block displays. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
154 lines
3.6 KiB
TypeScript
154 lines
3.6 KiB
TypeScript
export type Example = {
|
|
installCommands?: string[]
|
|
files?: {
|
|
name: string
|
|
content: string
|
|
}[]
|
|
}
|
|
|
|
const examples = {
|
|
nodejs: {
|
|
installCommands: ['npm install postgres'],
|
|
files: [
|
|
{
|
|
name: 'db.js',
|
|
content: `import postgres from 'postgres'
|
|
|
|
const connectionString = process.env.DATABASE_URL
|
|
const sql = postgres(connectionString)
|
|
|
|
export default sql`,
|
|
},
|
|
],
|
|
},
|
|
golang: {
|
|
installCommands: ['go get github.com/jackc/pgx/v5'],
|
|
files: [
|
|
{
|
|
name: 'main.go',
|
|
content: `package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"os"
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
func main() {
|
|
conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
|
|
if err != nil {
|
|
log.Fatalf("Failed to connect to the database: %v", err)
|
|
}
|
|
defer conn.Close(context.Background())
|
|
|
|
// Example query to test connection
|
|
var version string
|
|
if err := conn.QueryRow(context.Background(), "SELECT version()").Scan(&version); err != nil {
|
|
log.Fatalf("Query failed: %v", err)
|
|
}
|
|
|
|
log.Println("Connected to:", version)
|
|
}`,
|
|
},
|
|
],
|
|
},
|
|
dotnet: {
|
|
installCommands: [
|
|
// SSL Negotiation=Direct in the generated connection string requires Npgsql 9.0+.
|
|
// Concrete version: quoting a floating version breaks on Windows cmd, and
|
|
// floating versions fail under Central Package Management (NU1011).
|
|
'dotnet add package Npgsql --version 9.0.5',
|
|
'dotnet add package Microsoft.Extensions.Configuration.Json --version YOUR_DOTNET_VERSION',
|
|
],
|
|
},
|
|
python: {
|
|
installCommands: ['pip install python-dotenv psycopg2'],
|
|
files: [
|
|
{
|
|
name: 'main.py',
|
|
content: `import psycopg2
|
|
from dotenv import load_dotenv
|
|
import os
|
|
|
|
# Load environment variables from .env
|
|
load_dotenv()
|
|
|
|
# Fetch variables
|
|
USER = os.getenv("user")
|
|
PASSWORD = os.getenv("password")
|
|
HOST = os.getenv("host")
|
|
PORT = os.getenv("port")
|
|
DBNAME = os.getenv("dbname")
|
|
|
|
# Connect to the database
|
|
try:
|
|
connection = psycopg2.connect(
|
|
user=USER,
|
|
password=PASSWORD,
|
|
host=HOST,
|
|
port=PORT,
|
|
dbname=DBNAME
|
|
)
|
|
print("Connection successful!")
|
|
|
|
# Create a cursor to execute SQL queries
|
|
cursor = connection.cursor()
|
|
|
|
# Example query
|
|
cursor.execute("SELECT NOW();")
|
|
result = cursor.fetchone()
|
|
print("Current Time:", result)
|
|
|
|
# Close the cursor and connection
|
|
cursor.close()
|
|
connection.close()
|
|
print("Connection closed.")
|
|
|
|
except Exception as e:
|
|
print(f"Failed to connect: {e}")`,
|
|
},
|
|
],
|
|
},
|
|
sqlalchemy: {
|
|
installCommands: ['pip install python-dotenv sqlalchemy psycopg2'],
|
|
files: [
|
|
{
|
|
name: 'main.py',
|
|
content: `from sqlalchemy import create_engine
|
|
# from sqlalchemy.pool import NullPool
|
|
from dotenv import load_dotenv
|
|
import os
|
|
|
|
# Load environment variables from .env
|
|
load_dotenv()
|
|
|
|
# Fetch variables
|
|
USER = os.getenv("user")
|
|
PASSWORD = os.getenv("password")
|
|
HOST = os.getenv("host")
|
|
PORT = os.getenv("port")
|
|
DBNAME = os.getenv("dbname")
|
|
|
|
# Construct the SQLAlchemy connection string
|
|
DATABASE_URL = f"postgresql+psycopg2://{USER}:{PASSWORD}@{HOST}:{PORT}/{DBNAME}?sslmode=require"
|
|
|
|
# Create the SQLAlchemy engine
|
|
engine = create_engine(DATABASE_URL)
|
|
# If using Transaction Pooler or Session Pooler, we want to ensure we disable SQLAlchemy client side pooling -
|
|
# https://docs.sqlalchemy.org/en/20/core/pooling.html#switching-pool-implementations
|
|
# engine = create_engine(DATABASE_URL, poolclass=NullPool)
|
|
|
|
# Test the connection
|
|
try:
|
|
with engine.connect() as connection:
|
|
print("Connection successful!")
|
|
except Exception as e:
|
|
print(f"Failed to connect: {e}")`,
|
|
},
|
|
],
|
|
},
|
|
}
|
|
|
|
export default examples
|