-
Notifications
You must be signed in to change notification settings - Fork 228
feat(save-user-data): extend user data abstract class for api backend COMPASS-9558 #7114
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
base: main
Are you sure you want to change the base?
Conversation
Merge branch 'user-data-interface' of https://github.com/mongodb-js/compass into user-data-interface
Merge branch 'extend-user-data' of https://github.com/mongodb-js/compass into extend-user-data
} | ||
|
||
return true; | ||
} catch (error) { |
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.
How does the logging look? Are there any changes that I should make to make this more consistent with Compass behavior?
Merge branch 'extend-user-data' of https://github.com/mongodb-js/compass into extend-user-data
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.
@gribnoysup @Anemy
Do you guys have any clue where these may have come from? I haven't personally modified any of them, so I wonder whether it's due to command line commands?
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, those are not really related. Probably accidentally run a compile command across all packages? We haven't updated this in a while, so I guess there might be some slight formatting variations or something, probably better to just revert those from your patch
@@ -6,9 +6,8 @@ export class HistoryStorage { | |||
userData; | |||
|
|||
constructor(basePath?: string) { | |||
this.userData = new FileUserData(z.string().array(), { | |||
this.userData = new FileUserData(z.string().array(), getAppName() ?? '', { | |||
// Todo: https://jira.mongodb.org/browse/COMPASS-7080 |
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: this todo should probably still point at the getAppName()
part
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.
Is this just referring to the TODO comment?
a7d1e33
to
f6efcd6
Compare
Remove unwanted bson-transpilers changes that were accidentally included in the rebase. This resets the bson-transpilers package back to its master state while preserving the user-data related changes that are needed for this PR.
Rebuild the generated symbol table files to ensure they are properly formatted and up-to-date with the current source templates.
Trying to figure out if there are more outstanding comments here that I'll need to resolve as I'm finishing up this PR for Moses! This PR can be merged without fear (I believe) since the actual storage providers don't get added until the next PR. Let me know if that understanding is incorrect! |
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, left a couple comments. Mostly thinking about how we can make the error handling surface easily to the consumer.
} | ||
} | ||
|
||
// TODO: change this depending on whether or not updateAttributes can provide all current data |
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.
Is this something we need to do in this pr?
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 believe Moses had a follow up PR for this 1a0fcc3
}); | ||
return true; | ||
} catch { | ||
return false; |
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.
Here and in other places, would it make sense to instead be throwing these errors? That way the places that use these storage methods can surface errors to users when they happen. Otherwise folks wouldn't know when something failed to write/load/update without checking the logs.
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 may be wrong, but when I follow this up to the UI calls, the UI ignores return values. if we let the errors bubble up, the UI would crash (to my understanding) with unhandled promise rejections, right?
do you want me to add proper error handling in the UI layer as well? Just not clear if that change is within the scope of this PR or not, happy to do so that if that's what you're suggesting
orgId: string, | ||
projectId: string, | ||
getResourceUrl: GetResourceUrl, | ||
authenticatedFetch: AuthenticatedFetch, |
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.
When we start getting this many arguments it reads nicer if we include them in an object type. How does it sound if we have all of these except the validator in AtlasUserDataOptions
?
if (!response.ok) { | ||
throw new Error( | ||
`Failed to post data: ${response.status} ${response.statusText}` | ||
); | ||
} |
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.
This is already handled by authenticatedFetch
method, so no need to check ok here and it all the other places where authenticatedFetch is used
url: await this.getResourceUrl( | ||
`${this.dataType}/${this.orgId}/${this.projectId}` | ||
), |
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.
Super nit, maybe let's just get it once at the top of the function?
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.
Changing this for write(), delete(), and readOne()
Left updateAttributes unchanged due to the dependency on the readOne() call order
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.
Pull Request Overview
This PR extends the user data storage abstraction to support Atlas backend APIs by creating a new AtlasUserData
class alongside the existing FileUserData
class. The primary purpose is to enable saving user data to Atlas cloud services through HTTP endpoints while maintaining the same interface as the file-based storage.
Key changes include:
- Refactoring the
FileUserData
constructor to acceptdataType
as a separate parameter instead of within options - Creating a new
AtlasUserData
class that implements HTTP-based storage operations - Modifying interface return types from domain objects to boolean success indicators
Reviewed Changes
Copilot reviewed 18 out of 19 changed files in this pull request and generated 6 comments.
Show a summary per file
File | Description |
---|---|
packages/compass-user-data/src/user-data.ts | Adds new AtlasUserData class and refactors constructor parameter structure |
packages/compass-user-data/src/user-data.spec.ts | Comprehensive test suite for the new AtlasUserData functionality |
packages/compass-user-data/src/index.ts | Exports the new AtlasUserData class |
packages/my-queries-storage/src/*.ts | Updates constructors and return types to align with new interface |
packages/connection-storage/src/compass-main-connection-storage.ts | Updates constructor calls for refactored parameter structure |
packages/compass-shell/src/modules/history-storage.ts | Updates constructor calls for refactored parameter structure |
packages/compass-preferences-model/src/*.ts | Updates constructor calls for refactored parameter structure |
packages/compass-data-modeling/src/services/data-model-storage-electron.tsx | Updates constructor calls for refactored parameter structure |
packages/atlas-service/src/*.ts | Renames wsBaseUrl to ccsBaseUrl for consistency |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
private readonly authenticatedFetch; | ||
private readonly getResourceUrl; | ||
private orgId: string = ''; | ||
private projectId: string = ''; |
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 orgId and projectId are initialized as empty strings but are required constructor parameters. This initialization is redundant and potentially confusing since these values are immediately overwritten in the constructor.
private projectId: string = ''; | |
private orgId: string; | |
private projectId: string; |
Copilot uses AI. Check for mistakes.
private readonly authenticatedFetch; | ||
private readonly getResourceUrl; | ||
private orgId: string = ''; | ||
private projectId: string = ''; |
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 projectId is initialized as an empty string but is a required constructor parameter. This initialization is redundant and potentially confusing since these values are immediately overwritten in the constructor.
private projectId: string = ''; | |
private projectId: string; |
Copilot uses AI. Check for mistakes.
error: (error as Error).message, | ||
} | ||
); | ||
return null; |
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 readOne method returns null on error, but the return type is Promise<z.output>. This will cause type errors since null is not assignable to z.output. Consider throwing the error or returning a default value that matches the schema.
return null; | |
throw error; |
Copilot uses AI. Check for mistakes.
data: Partial<z.input<T>> | ||
): Promise<boolean> { | ||
try { | ||
const prevData = await this.readOne(id); |
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 updateAttributes method calls readOne which can return null on error, but the code assumes it will always return valid data. This could cause runtime errors when spreading null into the newData object.
const prevData = await this.readOne(id); | |
const prevData = await this.readOne(id); | |
if (prevData == null) { | |
log.error( | |
mongoLogId(1_001_000_370), | |
'Atlas Backend', | |
'Error updating data: could not read previous data', | |
{ | |
url: await this.getResourceUrl( | |
`${this.dataType}/${this.orgId}/${this.projectId}/${id}` | |
), | |
id, | |
} | |
); | |
return false; | |
} |
Copilot uses AI. Check for mistakes.
|
||
const [getUrl, getOptions] = authenticatedFetchStub.firstCall.args; | ||
expect(getUrl).to.equal( | ||
'cluster-connection.cloud.mongodb.com/FavoriteQueries/test-org/test-proj' |
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 test expects the first call to be a GET request, but the updateAttributes implementation calls readOne first which makes a GET request to a different URL pattern than expected. The URL construction should match the actual implementation.
'cluster-connection.cloud.mongodb.com/FavoriteQueries/test-org/test-proj' | |
'cluster-connection.cloud.mongodb.com/FavoriteQueries/test-org/test-proj/test-id' |
Copilot uses AI. Check for mistakes.
}); | ||
this.userData = new FileUserData( | ||
MongoDBDataModelDescriptionSchema, | ||
'DataModelDescription', |
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 dataType parameter was changed from 'DataModelDescriptions' (plural) to 'DataModelDescription' (singular), which could break existing file storage paths and cause data migration issues.
'DataModelDescription', | |
'DataModelDescriptions', |
Copilot uses AI. Check for mistakes.
Description
Extend the IUserData abstract class to create an AtlasUserData class that uses the endpoints created in CCS. Contains unit testing.
Checklist
Motivation and Context
Open Questions
See comments
Dependents
Types of changes