mirror of
https://github.com/lancedb/lancedb.git
synced 2026-10-17 09:12:28 +00:00
refactor!: implement lazy iterators for several APIs (#4459)
Implement lazy iterators for: - secrets - views - jobs - functions - materialized views
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
} from "./arrow";
|
||||
import { EmbeddingFunctionConfig, getRegistry } from "./embedding/registry";
|
||||
import { Job } from "./job";
|
||||
import { Listing, ListingOptions, validateListingOptions } from "./listing";
|
||||
import {
|
||||
MaterializedView,
|
||||
MaterializedViewSelect,
|
||||
@@ -347,9 +348,11 @@ export abstract class Connection {
|
||||
/**
|
||||
* The names of the materialized views in this database.
|
||||
*
|
||||
* Found by reading every table's schema, so this costs an open per table.
|
||||
* Iterate lazily with `for await...of`. Local listings inspect table schemas
|
||||
* one page at a time. Options control page size and the starting token.
|
||||
* See {@link Listing} for pagination state and error behavior.
|
||||
*/
|
||||
abstract listMaterializedViews(): Promise<string[]>;
|
||||
abstract listMaterializedViews(options?: ListingOptions): Listing<string>;
|
||||
|
||||
/**
|
||||
* Drop the materialized view named `name`.
|
||||
@@ -421,8 +424,13 @@ export abstract class Connection {
|
||||
* The names of the views in one namespace.
|
||||
*
|
||||
* Names only; a definition comes from {@link describeView}.
|
||||
* Iterate lazily with `for await...of`. See {@link Listing} for pagination
|
||||
* state and error behavior; options control page size and the starting token.
|
||||
*/
|
||||
abstract listViews(namespacePath?: string[]): Promise<string[]>;
|
||||
abstract listViews(
|
||||
namespacePath?: string[],
|
||||
options?: ListingOptions,
|
||||
): Listing<string>;
|
||||
|
||||
abstract openTable(
|
||||
name: string,
|
||||
@@ -637,8 +645,12 @@ export abstract class Connection {
|
||||
*/
|
||||
abstract openJob(jobId: string): Promise<Job>;
|
||||
|
||||
/** List server-side jobs across the database's tables. */
|
||||
abstract listJobs(): Promise<JobInfo[]>;
|
||||
/**
|
||||
* Iterate lazily over server-side jobs across the database's tables.
|
||||
* Use `for await...of`. Options control page size and the starting token.
|
||||
* See {@link Listing} for pagination state and error behavior.
|
||||
*/
|
||||
abstract listJobs(options?: ListingOptions): Listing<JobInfo>;
|
||||
|
||||
/**
|
||||
* Request cancellation of a server-side job by id.
|
||||
@@ -741,8 +753,11 @@ export class LocalConnection extends Connection {
|
||||
return new MaterializedView(new LocalTable(innerTable));
|
||||
}
|
||||
|
||||
async listMaterializedViews(): Promise<string[]> {
|
||||
return await this.inner.listMaterializedViews();
|
||||
listMaterializedViews(options: ListingOptions = {}): Listing<string> {
|
||||
validateListingOptions(options);
|
||||
return new Listing(
|
||||
this.inner.listMaterializedViews(options.pageToken, options.pageLimit),
|
||||
);
|
||||
}
|
||||
|
||||
async dropMaterializedView(
|
||||
@@ -788,8 +803,18 @@ export class LocalConnection extends Connection {
|
||||
return new Job(await this.inner.dropViewAsync(name, namespacePath ?? []));
|
||||
}
|
||||
|
||||
async listViews(namespacePath?: string[]): Promise<string[]> {
|
||||
return this.inner.listViews(namespacePath ?? []);
|
||||
listViews(
|
||||
namespacePath?: string[],
|
||||
options: ListingOptions = {},
|
||||
): Listing<string> {
|
||||
validateListingOptions(options);
|
||||
return new Listing(
|
||||
this.inner.listViews(
|
||||
namespacePath ?? [],
|
||||
options.pageToken,
|
||||
options.pageLimit,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async listTables(
|
||||
@@ -1057,8 +1082,11 @@ export class LocalConnection extends Connection {
|
||||
return new Job(await this.inner.openJob(jobId));
|
||||
}
|
||||
|
||||
async listJobs(): Promise<JobInfo[]> {
|
||||
return this.inner.listJobs();
|
||||
listJobs(options: ListingOptions = {}): Listing<JobInfo> {
|
||||
validateListingOptions(options);
|
||||
return new Listing(
|
||||
this.inner.listJobs(options.pageToken, options.pageLimit),
|
||||
);
|
||||
}
|
||||
|
||||
async cancelJob(jobId: string): Promise<boolean> {
|
||||
|
||||
@@ -649,3 +649,5 @@ export {
|
||||
DatabaseNames,
|
||||
connectCatalog,
|
||||
} from "./catalog";
|
||||
|
||||
export { Listing, ListingOptions } from "./listing";
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-FileCopyrightText: Copyright The LanceDB Authors
|
||||
|
||||
/** Pagination controls for lazy resource listings. */
|
||||
export interface ListingOptions {
|
||||
/** Starting continuation token; omitted starts at the beginning. */
|
||||
pageToken?: string;
|
||||
/** Maximum results per request, not a limit on the whole listing. */
|
||||
pageLimit?: number;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function validateListingOptions(options: ListingOptions): void {
|
||||
if (
|
||||
options.pageLimit !== undefined &&
|
||||
(!Number.isInteger(options.pageLimit) ||
|
||||
options.pageLimit <= 0 ||
|
||||
options.pageLimit > 2147483647)
|
||||
) {
|
||||
throw new Error(
|
||||
"Listing page limit must be an integer between 1 and 2147483647",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A lazy async iterator over database resources with pagination state.
|
||||
* Requests occur during iteration; request errors terminate the iterator.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* for await (const name of connection.listViews([], { pageLimit: 20 })) {
|
||||
* console.log(name);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export class Listing<T> implements AsyncIterableIterator<T> {
|
||||
/** @hidden */
|
||||
constructor(
|
||||
private readonly inner: {
|
||||
next(): Promise<T | null | undefined>;
|
||||
numPageResults(): number;
|
||||
pageToken(): string | null | undefined;
|
||||
},
|
||||
) {}
|
||||
|
||||
[Symbol.asyncIterator](): AsyncIterableIterator<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Fetch the next item, requesting another page only when needed. */
|
||||
async next(): Promise<IteratorResult<T>> {
|
||||
const value = await this.inner.next();
|
||||
return value == null
|
||||
? { done: true, value: undefined }
|
||||
: { done: false, value };
|
||||
}
|
||||
|
||||
/** Number of cached items available without another request. */
|
||||
numPageResults(): number {
|
||||
return this.inner.numPageResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Token for the next request. Initially this is the supplied starting token.
|
||||
* Returns undefined after fetching the final page, even with cached items.
|
||||
* Drain the cache before saving a token to avoid skipping items on resumption.
|
||||
* Failed requests terminate iteration and retain their token for a new iterator.
|
||||
*/
|
||||
pageToken(): string | undefined {
|
||||
return this.inner.pageToken() ?? undefined;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user