Skip to content
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

[feat] Add updateRemoteServer endpoint #5148

Merged
merged 15 commits into from
Apr 26, 2024

Conversation

ijreilly
Copy link
Collaborator

@ijreilly ijreilly commented Apr 24, 2024

Context

#4765

Following investigations (#5083) we decided to restrict updates of server from which zero tables have been synchronized only

How was it tested

Locally with /metadata

  1. Updating a database that already has synchronized tables
Capture d’écran 2024-04-24 à 16 16 05
  1. Updating a database that has no synchronized tables
Capture d’écran 2024-04-24 à 16 17 28 + tested that the connection works well

@ijreilly ijreilly marked this pull request as ready for review April 24, 2024 14:19
userMappingOptions: UserMappingOptions,
) {
// CURRENT_USER works for now since we are using only one user. But if we switch to a user per workspace, we need to change this.
return `ALTER USER MAPPING FOR CURRENT_USER SERVER "${foreignDataWrapperId}" OPTIONS (SET user '${userMappingOptions.username}', SET password '${userMappingOptions.password}')`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you assumes that all fields will always be present. But we should only update the fields that are defined

remoteServerId: string;
workspaceId: string;
}) {
const tables = await this.remoteTableRepository.find({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return this.remoteTableRepository.find({...

Then you do await findCurrentRemoteTablesByServerId. This way you let the caller decide if he wants to use the function asynchronously or synchronously


@IsOptional()
@Field(() => GraphQLJSON, { nullable: true })
userMappingOptions?: UserMappingOptions;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add some form of validation on this json type directly from graphql by creating an input type

@InputType()
class UserMappingOptionsInput {
  @Field(() => String)
  @IsString()
  username: string;

  @Field(() => String)
  @IsString()
  password: string;
}

or something like that, then

  @IsOptional()
  @Field(() => UserMappingOptionsInput, { nullable: true })
  userMappingOptions?: UserMappingOptionsInput;

If you don't want a new input type, you can also use class-validator and validate your json in your resolver like

class UserMappingOptionsValidator {
  @IsDefined()
  @IsString()
  username: string;

  @IsDefined()
  @IsString()
  password: string;
}

and then use validateOrReject from 'class-validator' package.
What do you think?

remoteServerInput: UpdateRemoteServerInput<T>,
workspaceId: string,
): Promise<RemoteServerEntity<RemoteServerType>> {
validateObject(remoteServerInput.foreignDataWrapperOptions);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I struggled to understand what validateObject does as it's very broad, I think we should fine a more explicit name @thomtrp

@@ -13,7 +13,7 @@ export const validateObject = (input: object) => {
}
};

export const validateString = (input: string) => {
export const validateStringRemoteServerInput = (input: string) => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed this but I am not sure what this validation is for on the id? @thomtrp

userMappingOptions?: Partial<UserMappingOptions>;
}

@InputType()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you put it in a separated file and use it in the create input too please?


if (remoteServerInput.userMappingOptions) {
validateObjectRemoteServerInput(remoteServerInput.userMappingOptions);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's have a global validation for create and update

[P in keyof T]?: DeepPartial<T[P]>;
};

export const updateRemoteServerRawQuery = (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suffix file name with .utils

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and please separate the functions that create the userMapping and the other options

Copy link
Contributor

@thomtrp thomtrp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥

@InputType()
export class UpdateRemoteServerInput<T extends RemoteServerType> {
@Field(() => String)
id: T;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is id a server type?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its a mistake thanks for spotting this !

continue;
}

if (!value || !INPUT_REGEX.test(value.toString())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry I think there is a misunderstood there. I don't think this is the role of this function to check if the value is not empty. If no value, just continue. If value, call validateStringAgainstInjections(value.toString())

@ijreilly ijreilly merged commit 76d4188 into main Apr 26, 2024
5 checks passed
@ijreilly ijreilly deleted the 4765--feat--update-server-connection branch April 26, 2024 16:12
arnavsaxena17 pushed a commit to arnavsaxena17/twenty that referenced this pull request Oct 6, 2024
## Context
twentyhq#4765 

Following investigations
([twentyhq#5083](twentyhq#5083)) we decided to
restrict updates of server from which zero tables have been synchronized
only

## How was it tested
Locally with /metadata
1. Updating a database that already has synchronized tables
<img width="1072" alt="Capture d’écran 2024-04-24 à 16 16 05"
src="https://github.com/twentyhq/twenty/assets/51697796/f9a84c34-2dcd-4f3c-b0bc-b710abae5021">

2. Updating a database that has no synchronized tables
<img width="843" alt="Capture d’écran 2024-04-24 à 16 17 28"
src="https://github.com/twentyhq/twenty/assets/51697796/f320fe03-a6bc-4724-bcd0-4e89d3ac31f5">
+ tested that the connection works well
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants