Skip to content

Commit

Permalink
update openapi core, implement new list feature for listing records b…
Browse files Browse the repository at this point in the history
…y id and prefix, add integration and unit tests
  • Loading branch information
austin-denoble committed Feb 21, 2024
1 parent 6461573 commit 5a7c90a
Show file tree
Hide file tree
Showing 64 changed files with 864 additions and 353 deletions.
4 changes: 2 additions & 2 deletions src/data/__tests__/deleteOne.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { deleteOne } from '../deleteOne';
import type {
DeleteOperationRequest,
VectorOperationsApi,
DataPlaneApi,
} from '../../pinecone-generated-ts-fetch';
import { VectorOperationsProvider } from '../vectorOperationsProvider';

Expand All @@ -11,7 +11,7 @@ const setupDeleteResponse = (response, isSuccess) => {
.mockImplementation(() =>
isSuccess ? Promise.resolve(response) : Promise.reject(response)
);
const VOA = { _delete: fakeDelete } as VectorOperationsApi;
const VOA = { _delete: fakeDelete } as DataPlaneApi;
const VoaProvider = { provide: async () => VOA } as VectorOperationsProvider;
return { VOA, VoaProvider };
};
Expand Down
4 changes: 2 additions & 2 deletions src/data/__tests__/describeIndexStats.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describeIndexStats } from '../describeIndexStats';
import { VectorOperationsApi } from '../../pinecone-generated-ts-fetch';
import { DataPlaneApi } from '../../pinecone-generated-ts-fetch';
import { VectorOperationsProvider } from '../vectorOperationsProvider';
import type { DescribeIndexStatsOperationRequest } from '../../pinecone-generated-ts-fetch';

Expand All @@ -13,7 +13,7 @@ const setupResponse = (response, isSuccess) => {
);
const VOA = {
describeIndexStats: fakeDescribeIndexStats,
} as VectorOperationsApi;
} as DataPlaneApi;
const VoaProvider = { provide: async () => VOA } as VectorOperationsProvider;
return { VOA, VoaProvider };
};
Expand Down
4 changes: 2 additions & 2 deletions src/data/__tests__/fetch.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { FetchCommand } from '../fetch';
import { VectorOperationsApi } from '../../pinecone-generated-ts-fetch';
import { DataPlaneApi } from '../../pinecone-generated-ts-fetch';
import { VectorOperationsProvider } from '../vectorOperationsProvider';
import type {
FetchRequest,
Expand All @@ -12,7 +12,7 @@ const setupResponse = (response, isSuccess) => {
.mockImplementation(() =>
isSuccess ? Promise.resolve(response) : Promise.reject(response)
);
const VOA = { fetch: fakeFetch } as VectorOperationsApi;
const VOA = { fetch: fakeFetch } as DataPlaneApi;
const VoaProvider = { provide: async () => VOA } as VectorOperationsProvider;
const cmd = new FetchCommand(VoaProvider, 'namespace');
return { VOA, VoaProvider, cmd };
Expand Down
43 changes: 43 additions & 0 deletions src/data/__tests__/list.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { list } from '../list';
import type {
ListRequest,
ListResponse,
DataPlaneApi,
} from '../../pinecone-generated-ts-fetch';
import { VectorOperationsProvider } from '../vectorOperationsProvider';

const setupListResponse = (response, isSuccess = true) => {
const fakeList: (req: ListRequest) => Promise<ListResponse> = jest
.fn()
.mockImplementation(() =>
isSuccess ? Promise.resolve(response) : Promise.reject(response)
);
const DPA = { list: fakeList } as DataPlaneApi;
const VoaProvider = { provide: async () => DPA } as VectorOperationsProvider;
return { DPA, VoaProvider };
};

describe('list', () => {
test('calls the openapi list endpoint, passing target namespace with ListOptions', async () => {
const listResponse = {
vectors: [
{ id: 'prefix-1', values: [0.2, 0.4] },
{ id: 'prefix-2', values: [0.3, 0.5] },
{ id: 'prefix-3', values: [0.4, 0.6] },
],
pagination: { next: 'fake-pagination-token-123123123' },
namespace: 'list-namespace',
usage: { readUnits: 1 },
};
const { VoaProvider, DPA } = setupListResponse(listResponse);

const listFn = list(VoaProvider, 'list-namespace');
const returned = await listFn({ prefix: 'prefix-' });

expect(returned).toBe(listResponse);
expect(DPA.list).toHaveBeenCalledWith({
prefix: 'prefix-',
namespace: 'list-namespace',
});
});
});
4 changes: 2 additions & 2 deletions src/data/__tests__/update.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { UpdateCommand } from '../update';
import { VectorOperationsApi } from '../../pinecone-generated-ts-fetch';
import { DataPlaneApi } from '../../pinecone-generated-ts-fetch';
import { VectorOperationsProvider } from '../vectorOperationsProvider';
import type { UpdateOperationRequest } from '../../pinecone-generated-ts-fetch';

Expand All @@ -9,7 +9,7 @@ const setupResponse = (response, isSuccess) => {
.mockImplementation(() =>
isSuccess ? Promise.resolve(response) : Promise.reject(response)
);
const VOA = { update: fakeUpdate } as VectorOperationsApi;
const VOA = { update: fakeUpdate } as DataPlaneApi;
const VoaProvider = { provide: async () => VOA } as VectorOperationsProvider;
const cmd = new UpdateCommand(VoaProvider, 'namespace');
return { fakeUpdate, VOA, VoaProvider, cmd };
Expand Down
4 changes: 2 additions & 2 deletions src/data/__tests__/upsert.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { UpsertCommand } from '../upsert';
import { VectorOperationsApi } from '../../pinecone-generated-ts-fetch';
import { DataPlaneApi } from '../../pinecone-generated-ts-fetch';
import type { UpsertOperationRequest } from '../../pinecone-generated-ts-fetch';
import { VectorOperationsProvider } from '../vectorOperationsProvider';

Expand All @@ -9,7 +9,7 @@ const setupResponse = (response, isSuccess) => {
.mockImplementation(() =>
isSuccess ? Promise.resolve(response) : Promise.reject(response)
);
const VOA = { upsert: fakeUpsert } as VectorOperationsApi;
const VOA = { upsert: fakeUpsert } as DataPlaneApi;
const VoaProvider = { provide: async () => VOA } as VectorOperationsProvider;
const cmd = new UpsertCommand(VoaProvider, 'namespace');

Expand Down
21 changes: 19 additions & 2 deletions src/data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ import type { UpdateOptions } from './update';
import { QueryCommand } from './query';
import type { QueryOptions } from './query';
import { deleteOne } from './deleteOne';
import type { DeleteOneOptions } from './deleteOne';
import { deleteMany } from './deleteMany';
import type { DeleteManyOptions } from './deleteMany';
import { deleteAll } from './deleteAll';
import { describeIndexStats } from './describeIndexStats';
import { list } from './list';
import type { ListOptions } from './list';
import { VectorOperationsProvider } from './vectorOperationsProvider';
import type {
PineconeConfiguration,
Expand Down Expand Up @@ -47,6 +51,7 @@ export type {
QueryResponse,
QueryShared,
} from './query';
export type { ListOptions } from './list';

/**
* The `Index` class is used to perform data operations (upsert, query, etc)
Expand Down Expand Up @@ -185,7 +190,7 @@ export class Index<T extends RecordMetadata = RecordMetadata> {
* @returns A promise that resolves when the delete is completed.
* @throws {@link Errors.PineconeArgumentError} when invalid arguments are passed.
*/
deleteMany(options) {
deleteMany(options: DeleteManyOptions) {
return this._deleteMany(options);
}
/** @hidden */
Expand All @@ -203,7 +208,7 @@ export class Index<T extends RecordMetadata = RecordMetadata> {
* @returns A promise that resolves when the delete is completed.
* @throws {@link Errors.PineconeArgumentError} when invalid arguments are passed.
*/
deleteOne(id) {
deleteOne(id: DeleteOneOptions) {
return this._deleteOne(id);
}
/** @hidden */
Expand Down Expand Up @@ -236,6 +241,17 @@ export class Index<T extends RecordMetadata = RecordMetadata> {
/** @hidden */
_describeIndexStats: ReturnType<typeof describeIndexStats>;

/**
* TODO - describe list operations for docs
* @param options
* @returns
*/
list(options?: ListOptions) {
return this._list(options);
}
/** @hidden */
_list: ReturnType<typeof list>;

/** @hidden */
private _fetchCommand: FetchCommand<T>;
/** @hidden */
Expand Down Expand Up @@ -283,6 +299,7 @@ export class Index<T extends RecordMetadata = RecordMetadata> {
this._deleteMany = deleteMany(apiProvider, namespace);
this._deleteOne = deleteOne(apiProvider, namespace);
this._describeIndexStats = describeIndexStats(apiProvider);
this._list = list(apiProvider, namespace);

this._fetchCommand = new FetchCommand<T>(apiProvider, namespace);
this._queryCommand = new QueryCommand<T>(apiProvider, namespace);
Expand Down
38 changes: 38 additions & 0 deletions src/data/list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { buildConfigValidator } from '../validator';
import { Type } from '@sinclair/typebox';
import { VectorOperationsProvider } from './vectorOperationsProvider';
import type { ListRequest, ListResponse } from '../pinecone-generated-ts-fetch';

export type ListOptions = {
prefix?: string;
limit?: number;
paginationToken?: string;
};

const ListOptionsSchema = Type.Object(
{
prefix: Type.Optional(Type.String({ minLength: 1 })),
limit: Type.Optional(Type.Number()),
paginationToken: Type.Optional(Type.String({ minLength: 1 })),
},
{ additionalProperties: false }
);

export const list = (
apiProvider: VectorOperationsProvider,
namespace: string
) => {
const validator = buildConfigValidator(ListOptionsSchema, 'list');

return async (options?: ListOptions): Promise<ListResponse> => {
validator(options);

const listRequest: ListRequest = {
...options,
namespace,
};

const api = await apiProvider.provide();
return await api.list(listRequest);
};
};
6 changes: 3 additions & 3 deletions src/data/vectorOperationsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { PineconeConfiguration } from './types';
import {
Configuration,
ConfigurationParameters,
VectorOperationsApi,
DataPlaneApi,
} from '../pinecone-generated-ts-fetch';
import {
queryParamsStringify,
Expand All @@ -17,7 +17,7 @@ export class VectorOperationsProvider {
private config: PineconeConfiguration;
private indexName: string;
private indexHostUrl?: string;
private vectorOperations?: VectorOperationsApi;
private vectorOperations?: DataPlaneApi;

constructor(
config: PineconeConfiguration,
Expand Down Expand Up @@ -63,7 +63,7 @@ export class VectorOperationsProvider {
};

const indexConfiguration = new Configuration(indexConfigurationParameters);
const vectorOperations = new VectorOperationsApi(indexConfiguration);
const vectorOperations = new DataPlaneApi(indexConfiguration);

return vectorOperations;
}
Expand Down
4 changes: 2 additions & 2 deletions src/integration/data/delete.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('delete', () => {
});

test('verify delete with id', async () => {
const recordToUpsert = generateRecords(5, 1);
const recordToUpsert = generateRecords({ dimension: 5, quantity: 1 });
recordIds = recordToUpsert.map((r) => r.id);
expect(recordToUpsert).toHaveLength(1);
expect(recordToUpsert[0].id).toEqual(recordIds[0]);
Expand Down Expand Up @@ -83,7 +83,7 @@ describe('delete', () => {
});

test('verify deleteMany with ids', async () => {
const recordsToUpsert = generateRecords(5, 3);
const recordsToUpsert = generateRecords({ dimension: 5, quantity: 3 });
recordIds = recordsToUpsert.map((r) => r.id);
expect(recordsToUpsert).toHaveLength(3);
expect(recordsToUpsert[0].id).toEqual('0');
Expand Down
2 changes: 1 addition & 1 deletion src/integration/data/fetch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('fetch', () => {
});

test('fetch by id', async () => {
const recordsToUpsert = generateRecords(5, 3);
const recordsToUpsert = generateRecords({ dimension: 5, quantity: 3 });
recordIds = recordsToUpsert.map((r) => r.id);
expect(recordsToUpsert).toHaveLength(3);
expect(recordsToUpsert[0].id).toEqual('0');
Expand Down
87 changes: 87 additions & 0 deletions src/integration/data/list.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Pinecone, Index } from '../../index';
import {
generateRecords,
randomString,
INDEX_NAME,
waitUntilRecordsReady,
} from '../test-helpers';

describe('list', () => {
let pinecone: Pinecone,
index: Index,
ns: Index,
namespace: string,
prefix: string,
recordIds: string[];

beforeAll(async () => {
pinecone = new Pinecone();

await pinecone.createIndex({
name: INDEX_NAME,
dimension: 5,
metric: 'cosine',
spec: {
serverless: {
region: 'us-west-2',
cloud: 'aws',
},
},
waitUntilReady: true,
suppressConflicts: true,
});

namespace = randomString(16);
index = pinecone.index(INDEX_NAME);
ns = index.namespace(namespace);
prefix = 'preTest-';

// Seed the namespace with records for testing
const recordsToUpsert = generateRecords({
dimension: 5,
quantity: 120,
prefix,
});
const upsertedIds = recordsToUpsert.map((r) => r.id);

await ns.upsert(recordsToUpsert);
await waitUntilRecordsReady(ns, namespace, upsertedIds);
recordIds.concat(upsertedIds);
});

afterAll(async () => {
await ns.deleteMany(recordIds);
});

test('test list with no arguments', async () => {
const listResults = await index.list();
expect(listResults).toBeDefined();
expect(listResults.pagination).not.toBeDefined();
expect(listResults.vectors?.length).toBe(0);
expect(listResults.namespace).toBe(namespace);
});

test('test list with prefix', async () => {
const listResults = await ns.list({ prefix });
expect(listResults.namespace).toBe(namespace);
expect(listResults.vectors?.length).toBe(recordIds.length);
expect(listResults.pagination?.next).toBeDefined();
});

test('test list with limit and pagination', async () => {
const listResults = await ns.list({ prefix, limit: 60 });
expect(listResults.namespace).toBe(namespace);
expect(listResults.vectors?.length).toBe(60);
expect(listResults.pagination?.next).toBeDefined();

const listResultsPg2 = await ns.list({
prefix,
limit: 60,
paginationToken: listResults.pagination?.next,
});

expect(listResultsPg2.namespace).toBe(namespace);
expect(listResultsPg2.vectors?.length).toBe(60);
expect(listResultsPg2.pagination?.next).not.toBeDefined();
});
});
Loading

0 comments on commit 5a7c90a

Please sign in to comment.