-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[v1] Implement collection operations #70
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like to all these beautiful tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work! Big fan of the attention to DevX. Still using PRs as a way of getting up to speed, nothing majorly blocking 🚀
const listCollectionsError = e as ResponseError; | ||
throw mapHttpStatusError({ | ||
status: listCollectionsError.response.status, | ||
url: listCollectionsError.response.url, | ||
message: await listCollectionsError.response.text(), | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd conveniently forgotten that JS error catching is... so rough.
nit Would it help to be a bit defensive here and do an instanceof ResponseError
check in case this isn't for whatever reason a ResponseError
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good thought. I will add a follow-up task to my todo list.
export const listCollections = (api: IndexOperationsApi) => { | ||
return async (): Promise<CollectionList> => { | ||
try { | ||
return await api.listCollections(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit I think you can just return api.listCollections()
if the intent is to return a promise, since you'd have to await
on the other end anyway, right? Same for anywhere you return await
.
export { listCollections } from './listCollections'; | ||
export { deleteCollection } from './deleteCollection'; | ||
|
||
export type { CollectionName, CollectionList } from './listCollections'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<3
// If user passes the empty string for collection name, the generated | ||
// OpenAPI client will call /databases/ which is the list | ||
// collection endpoint. This returns 200 instead of 404, but obviously | ||
// no descriptive information is returned for an collection named empty | ||
// string. To avoid this confusing case, we require lenth > 1. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤩
const DescribeCollectionSchema = Type.String({ minLength: 1 }); | ||
|
||
export type CollectionName = Static<typeof DescribeCollectionSchema>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very cool! I know @zaeemadamjee mentioned he was looking at zod
for something on the console-side. Probably not too important to do now, but think it might be nice to align on a single tool at some point
const removeDeprecatedFields = (result: any) => { | ||
if (result.database) { | ||
for (const key of Object.keys(result.database)) { | ||
if (result.database[key] === undefined) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question Is it always going to be true that an undefined
value is always deprecated? I'm wondering if it's safer to allow/deny-list fields and build a new object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's on my todo list to dig into this question more. Probably for the long term we want some way to distinguish deprecated from undefined.
|
||
try { | ||
await api.deleteCollection({ collectionName: collectionName }); | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought I think I'm elixir-braining this a bit so you can ignore if you want--Do we want to pass along some kind of indicator of success or is undefined
standard practice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The overall return value here is Promise<void>
which I think makes sense. I considered this question when I was implementing and couldn't think of anything very meaningful to return; on success the underlying generated openapi client just returns ''
when deleting which I don't think adds any information and can actually be misleading because ''
is a falsy value even though it succeeded.
If the request fails, this will throw and the promise will be rejected. Some APIs echo back the name/id of the thing that was deleted or a delete count when deleting multiple records, but our API doesn't return those today and to me it doesn't seem that useful anyway. As a caller, if I ask an api to return collection 'foo'
and it says it succeeded, I already know everything I need to know about the state of the world.
source: nonemptyString, | ||
}); | ||
|
||
export type CreateCollectionOptions = Static< |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LOL, line length limits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the line length formatting has honestly been a big pain because // @ts-ignore
doesn't work if things break across two lines and a lot of my test cases are specifically passing params that violate the typescript expectations to test method validation. Thinking about disabling that formatting rule.
import { IndexOperationsApi } from '../../pinecone-generated-ts-fetch'; | ||
import type { CreateCollectionOperationRequest as CCOR } from '../../pinecone-generated-ts-fetch'; | ||
|
||
const setOpenAPIResponse = (fakeCreateCollectionResponse) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion For the future, I think potentially a better way to do this would mock of IOA could be to use jest manual mocks but I think typing this could be hellish too...
d511d07
to
ace0c53
Compare
Problem
Similar to recent PRs #66 and #67, this PR is adding new functionality to the revamped node client. Specifically:
createCollection
describeCollection
listCollections
deleteCollection
Solution
More or less followed the approach used in #66 and #67 to provide simpler arguments, runtime argument validation, and improved error handling.
Type of Change
Test Plan
npm run repl
Creating a collection
Validating arguments
bad request
happy path
describeCollection
Validations
bad request
happy path
listCollection
deleteCollection