diff --git a/docs/web-tests/py/test_connection.py b/docs/web-tests/py/test_connection.py index 783ac2d8d..92fb963e6 100644 --- a/docs/web-tests/py/test_connection.py +++ b/docs/web-tests/py/test_connection.py @@ -4,6 +4,8 @@ from pathlib import Path import shutil +import pytest + def test_connection(): # --8<-- [start:connect] @@ -29,19 +31,16 @@ async def connect_async_example(): def connect_enterprise_quickstart_config(): + # --8<-- [start:connect_enterprise_quickstart] + import os + import lancedb - # --8<-- [start:connect_enterprise_quickstart] - uri = "db://your-database-uri" - api_key = "your-api-key" - region = "us-east-1" - host_override = "https://your-enterprise-endpoint.com" - db = lancedb.connect( - uri=uri, - api_key=api_key, - region=region, - host_override=host_override, + uri=os.environ["LANCEDB_URI"], # db://your-database + api_key=os.environ["LANCEDB_API_KEY"], + region=os.environ.get("LANCEDB_REGION", "us-east-1"), + host_override=os.environ["LANCEDB_HOST_OVERRIDE"], # https://your-endpoint ) # --8<-- [end:connect_enterprise_quickstart] return db @@ -57,17 +56,29 @@ def test_connect_enterprise_quickstart(monkeypatch): return object() monkeypatch.setattr(lancedb, "connect", fake_connect) + monkeypatch.setenv("LANCEDB_URI", "db://your-database") + monkeypatch.setenv("LANCEDB_API_KEY", "your-api-key") + monkeypatch.delenv("LANCEDB_REGION", raising=False) + monkeypatch.setenv("LANCEDB_HOST_OVERRIDE", "https://your-endpoint") - db = connect_enterprise_quickstart_config() - assert db is not None + assert connect_enterprise_quickstart_config() is not None assert captured == { - "uri": "db://your-database-uri", + "uri": "db://your-database", "api_key": "your-api-key", "region": "us-east-1", - "host_override": "https://your-enterprise-endpoint.com", + "host_override": "https://your-endpoint", } +def test_connect_enterprise_quickstart_requires_an_endpoint(monkeypatch): + monkeypatch.setenv("LANCEDB_URI", "db://your-database") + monkeypatch.setenv("LANCEDB_API_KEY", "your-api-key") + monkeypatch.delenv("LANCEDB_HOST_OVERRIDE", raising=False) + + with pytest.raises(KeyError, match="LANCEDB_HOST_OVERRIDE"): + connect_enterprise_quickstart_config() + + def connect_object_storage_config(): # --8<-- [start:connect_object_storage] import lancedb diff --git a/docs/web-tests/rs/connection.rs b/docs/web-tests/rs/connection.rs index 4f7212ef5..a127c7060 100644 --- a/docs/web-tests/rs/connection.rs +++ b/docs/web-tests/rs/connection.rs @@ -23,19 +23,15 @@ async fn main() { let _ = connect_object_storage_config(); } -fn connect_enterprise_quickstart_config() -> (String, String, String, String) { +fn connect_enterprise_quickstart_config() +-> Result<(String, String, String, String), std::env::VarError> { // --8<-- [start:connect_enterprise_quickstart] - let uri = "db://your-database-uri"; - let api_key = "your-api-key"; - let region = "us-east-1"; - let host_override = "https://your-enterprise-endpoint.com"; + let uri = std::env::var("LANCEDB_URI")?; // db://your-database + let api_key = std::env::var("LANCEDB_API_KEY")?; + let region = std::env::var("LANCEDB_REGION").unwrap_or_else(|_| "us-east-1".to_string()); + let host_override = std::env::var("LANCEDB_HOST_OVERRIDE")?; // https://your-endpoint // --8<-- [end:connect_enterprise_quickstart] - ( - uri.to_string(), - api_key.to_string(), - region.to_string(), - host_override.to_string(), - ) + Ok((uri, api_key, region, host_override)) } fn connect_object_storage_config() -> &'static str { diff --git a/docs/web-tests/ts/connection.test.ts b/docs/web-tests/ts/connection.test.ts index f522654ec..e1574976c 100644 --- a/docs/web-tests/ts/connection.test.ts +++ b/docs/web-tests/ts/connection.test.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright The LanceDB Authors -import { expect, jest, test } from "@jest/globals"; +import { afterEach, describe, expect, jest, test } from "@jest/globals"; import * as path from "node:path"; import { withTempDirectory } from "./util.ts"; // --8<-- [start:connect] @@ -22,34 +22,56 @@ test("connect to a local database", async () => { async function connectEnterpriseQuickstart() { // --8<-- [start:connect_enterprise_quickstart] - const uri = "db://your-database-uri"; - const apiKey = "your-api-key"; - const region = "us-east-1"; - const hostOverride = "https://your-enterprise-endpoint.com"; + const setting = (name: string) => { + const value = process.env[name]; + if (!value) throw new Error(`Set ${name}`); + return value; + }; - const db = await lancedb.connect(uri, { - apiKey, - region, - hostOverride, + const db = await lancedb.connect(setting("LANCEDB_URI"), { + apiKey: setting("LANCEDB_API_KEY"), + region: process.env.LANCEDB_REGION ?? "us-east-1", + hostOverride: setting("LANCEDB_HOST_OVERRIDE"), }); // --8<-- [end:connect_enterprise_quickstart] return db; } -test("enterprise quickstart connect uses placeholder config", async () => { - const mockDb = { __mock: true } as unknown as Awaited< - ReturnType - >; - const spy = jest.spyOn(lancedb, "connect").mockResolvedValue(mockDb); - - const db = await connectEnterpriseQuickstart(); - expect(db).toBe(mockDb); - expect(spy).toHaveBeenCalledWith("db://your-database-uri", { - apiKey: "your-api-key", - region: "us-east-1", - hostOverride: "https://your-enterprise-endpoint.com", +describe("enterprise quickstart connect", () => { + const saved = { ...process.env }; + afterEach(() => { + process.env = { ...saved }; + }); + + test("reads the connection from the environment", async () => { + const mockDb = { __mock: true } as unknown as Awaited< + ReturnType + >; + const spy = jest.spyOn(lancedb, "connect").mockResolvedValue(mockDb); + process.env.LANCEDB_URI = "db://your-database"; + process.env.LANCEDB_API_KEY = "your-api-key"; + delete process.env.LANCEDB_REGION; + process.env.LANCEDB_HOST_OVERRIDE = "https://your-endpoint"; + + const db = await connectEnterpriseQuickstart(); + expect(db).toBe(mockDb); + expect(spy).toHaveBeenCalledWith("db://your-database", { + apiKey: "your-api-key", + region: "us-east-1", + hostOverride: "https://your-endpoint", + }); + spy.mockRestore(); + }); + + test("requires an endpoint", async () => { + process.env.LANCEDB_URI = "db://your-database"; + process.env.LANCEDB_API_KEY = "your-api-key"; + delete process.env.LANCEDB_HOST_OVERRIDE; + + await expect(connectEnterpriseQuickstart()).rejects.toThrow( + "Set LANCEDB_HOST_OVERRIDE", + ); }); - spy.mockRestore(); }); // --8<-- [start:connect_object_storage] diff --git a/docs/web/api-reference/rest/index.mdx b/docs/web/api-reference/rest/index.mdx index 805f73cda..b2dd10016 100644 --- a/docs/web/api-reference/rest/index.mdx +++ b/docs/web/api-reference/rest/index.mdx @@ -35,10 +35,13 @@ To authenticate to the Enterprise REST API, you need the endpoint for your deplo ```bash export LANCEDB_API_KEY="" -export LANCEDB_URI="https://your-enterprise-endpoint.com" +export LANCEDB_HOST_OVERRIDE="https://your-enterprise-endpoint.com" export LANCEDB_DATABASE="your-database-name" ``` +`LANCEDB_HOST_OVERRIDE` is the endpoint the SDKs take as `host_override`; the +database name is the part of its `db://` URI after `db://`. + 3. If your Enterprise deployment is private, connect through the private network endpoint provided for your deployment. For example, Azure Private Link deployments commonly use a private IP or an internal DNS name as the endpoint. ### Verify authentication {#verify-authentication} @@ -46,30 +49,37 @@ export LANCEDB_DATABASE="your-database-name" 4. Check that you can reach the deployment and list tables: ```bash -curl -X GET "$LANCEDB_URI/v1/management/table" \ - -H "Content-Type: application/json" \ +curl -X GET "$LANCEDB_HOST_OVERRIDE/v1/table/" \ -H "x-api-key: $LANCEDB_API_KEY" \ -H "x-lancedb-database: $LANCEDB_DATABASE" ``` +The response lists one page of table names, with a token for the next page when +there are more. + If your deployment endpoint already includes the database host name, you can omit the `x-lancedb-database` header. -5. Create a table to confirm write access. Let's call it `words`. +5. Create a table to confirm write access. Let's call it `words`. A table is +created from an Arrow IPC stream, which this writes with PyArrow: ```bash -curl -X POST "$LANCEDB_URI/v1/tables/words" \ +python -c "import pyarrow as pa, sys; t = pa.table({'word': ['hello', 'world']}); w = pa.ipc.new_stream(sys.stdout.buffer, t.schema); w.write_table(t); w.close()" > words.arrow + +curl -X POST "$LANCEDB_HOST_OVERRIDE/v1/table/words/create" \ -H "Content-Type: application/vnd.apache.arrow.stream" \ -H "x-api-key: $LANCEDB_API_KEY" \ - -H "x-lancedb-database: $LANCEDB_DATABASE" + -H "x-lancedb-database: $LANCEDB_DATABASE" \ + --data-binary @words.arrow ``` 6. Check that the table has been created: ```bash -curl -X GET "$LANCEDB_URI/v1/management/table" \ +curl -X POST "$LANCEDB_HOST_OVERRIDE/v1/table/words/describe" \ -H "Content-Type: application/json" \ -H "x-api-key: $LANCEDB_API_KEY" \ - -H "x-lancedb-database: $LANCEDB_DATABASE" + -H "x-lancedb-database: $LANCEDB_DATABASE" \ + -d '{}' ``` That's it -- you're connected! Now, you can start adding data and querying it. diff --git a/docs/web/basics/connect.mdx b/docs/web/basics/connect.mdx index 3b4bf5111..4ec5aa599 100644 --- a/docs/web/basics/connect.mdx +++ b/docs/web/basics/connect.mdx @@ -80,12 +80,12 @@ In Rust, pass the same URI to `connect`. A `db://` URI connects to a deployment, which runs each operation for you. Get the database URI, API key, region and endpoint from the deployment's -administrator, and pass the endpoint as `host_override`. Keep the API key in a -secret manager or the environment rather than in source. +administrator. These examples read them from `LANCEDB_URI`, `LANCEDB_API_KEY`, +`LANCEDB_REGION` and `LANCEDB_HOST_OVERRIDE`, which keeps the API key out of +source, and pass the endpoint as `host_override`. - { "import lancedb\n\n" } {PyConnectEnterpriseQuickstart} diff --git a/docs/web/quickstart.mdx b/docs/web/quickstart.mdx index a507bba96..d4b14ac71 100644 --- a/docs/web/quickstart.mdx +++ b/docs/web/quickstart.mdx @@ -184,12 +184,12 @@ For credentials, endpoints, and provider-specific options, see If you're using LanceDB Enterprise, you can connect to the remote database using the `db://` URI along with the API key, region, and cluster endpoint you received from the -LanceDB team. Pass the cluster endpoint via `host_override` so the client routes -requests to your deployment. +LanceDB team. These examples read them from `LANCEDB_URI`, `LANCEDB_API_KEY`, +`LANCEDB_REGION` and `LANCEDB_HOST_OVERRIDE`, and pass the cluster endpoint via +`host_override` so the client routes requests to your deployment. - { "import lancedb\n\n" } {PyConnectEnterpriseQuickstart} @@ -199,7 +199,6 @@ requests to your deployment. - { "use lancedb::connect;\n\n" } {RsConnectEnterpriseQuickstart} diff --git a/docs/web/snippets/connection.mdx b/docs/web/snippets/connection.mdx index c7d8a187d..d359a02f2 100644 --- a/docs/web/snippets/connection.mdx +++ b/docs/web/snippets/connection.mdx @@ -4,7 +4,7 @@ export const PyConnect = "import lancedb\n\nuri = \"ex_lancedb\"\ndb = lancedb.c export const PyConnectAsync = "import lancedb\n\nuri = \"ex_lancedb\"\nasync_db = await lancedb.connect_async(uri)\n"; -export const PyConnectEnterpriseQuickstart = "uri = \"db://your-database-uri\"\napi_key = \"your-api-key\"\nregion = \"us-east-1\"\nhost_override = \"https://your-enterprise-endpoint.com\"\n\ndb = lancedb.connect(\n uri=uri,\n api_key=api_key,\n region=region,\n host_override=host_override,\n)\n"; +export const PyConnectEnterpriseQuickstart = "import os\n\nimport lancedb\n\ndb = lancedb.connect(\n uri=os.environ[\"LANCEDB_URI\"], # db://your-database\n api_key=os.environ[\"LANCEDB_API_KEY\"],\n region=os.environ.get(\"LANCEDB_REGION\", \"us-east-1\"),\n host_override=os.environ[\"LANCEDB_HOST_OVERRIDE\"], # https://your-endpoint\n)\n"; export const PyConnectObjectStorage = "import lancedb\n\nuri = \"s3://your-bucket/path\"\n# You can also use \"gs://your-bucket/path\" or \"az://your-container/path\".\ndb = lancedb.connect(uri)\n"; @@ -16,7 +16,7 @@ export const PyNamespaceTableOps = "import lancedb\n\ndb = lancedb.connect_names export const TsConnect = "import * as lancedb from \"@lancedb/lancedb\";\n\nasync function connectExample(uri: string) {\n const db = await lancedb.connect(uri);\n return db;\n}\n"; -export const TsConnectEnterpriseQuickstart = "const uri = \"db://your-database-uri\";\nconst apiKey = \"your-api-key\";\nconst region = \"us-east-1\";\nconst hostOverride = \"https://your-enterprise-endpoint.com\";\n\nconst db = await lancedb.connect(uri, {\n apiKey,\n region,\n hostOverride,\n});\n"; +export const TsConnectEnterpriseQuickstart = "const setting = (name: string) => {\n const value = process.env[name];\n if (!value) throw new Error(`Set ${name}`);\n return value;\n};\n\nconst db = await lancedb.connect(setting(\"LANCEDB_URI\"), {\n apiKey: setting(\"LANCEDB_API_KEY\"),\n region: process.env.LANCEDB_REGION ?? \"us-east-1\",\n hostOverride: setting(\"LANCEDB_HOST_OVERRIDE\"),\n});\n"; export const TsConnectObjectStorage = "async function connectObjectStorageExample() {\n const uri = \"s3://your-bucket/path\";\n // You can also use \"gs://your-bucket/path\" or \"az://your-container/path\".\n const db = await lancedb.connect(uri);\n return db;\n}\n"; @@ -26,7 +26,7 @@ export const TsNamespaceTableOps = "const db = await lancedb.connectNamespace(\" export const RsConnect = "async fn connect_example(uri: &str) {\n let db = connect(uri).execute().await.unwrap();\n let _ = db;\n}\n"; -export const RsConnectEnterpriseQuickstart = "let uri = \"db://your-database-uri\";\nlet api_key = \"your-api-key\";\nlet region = \"us-east-1\";\nlet host_override = \"https://your-enterprise-endpoint.com\";\n"; +export const RsConnectEnterpriseQuickstart = "let uri = std::env::var(\"LANCEDB_URI\")?; // db://your-database\nlet api_key = std::env::var(\"LANCEDB_API_KEY\")?;\nlet region = std::env::var(\"LANCEDB_REGION\").unwrap_or_else(|_| \"us-east-1\".to_string());\nlet host_override = std::env::var(\"LANCEDB_HOST_OVERRIDE\")?; // https://your-endpoint\n"; export const RsConnectObjectStorage = "let uri = \"s3://your-bucket/path\";\n// You can also use \"gs://your-bucket/path\" or \"az://your-container/path\".\n";