Build stripe integration on backend side (#5246)
Adding stripe integration by making the server logic independent of the input fields: - query factories (remote server, foreign data wrapper, foreign table) to loop on fields and values without hardcoding the names of the fields - adding stripe input and type - add the logic to handle static schema. Simply creating a big object to store into the server Additional work: - rename username field to user. This is the input intended for postgres user mapping and we now need a matching by name --------- Co-authored-by: Thomas Trompette <thomast@twenty.com>
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import { ForeignDataWrapperQueryFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/foreign-data-wrapper-query.factory';
|
||||
import { ForeignDataWrapperServerQueryFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/foreign-data-wrapper-server-query.factory';
|
||||
|
||||
import { ArgsAliasFactory } from './args-alias.factory';
|
||||
import { ArgsStringFactory } from './args-string.factory';
|
||||
@ -30,5 +30,5 @@ export const workspaceQueryBuilderFactories = [
|
||||
UpdateOneQueryFactory,
|
||||
UpdateManyQueryFactory,
|
||||
DeleteManyQueryFactory,
|
||||
ForeignDataWrapperQueryFactory,
|
||||
ForeignDataWrapperServerQueryFactory,
|
||||
];
|
||||
|
||||
@ -1,105 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'class-validator';
|
||||
|
||||
import {
|
||||
ForeignDataWrapperOptions,
|
||||
RemoteServerType,
|
||||
} from 'src/engine/metadata-modules/remote-server/remote-server.entity';
|
||||
import { UserMappingOptions } from 'src/engine/metadata-modules/remote-server/utils/user-mapping-options.utils';
|
||||
|
||||
@Injectable()
|
||||
export class ForeignDataWrapperQueryFactory {
|
||||
createForeignDataWrapper(
|
||||
foreignDataWrapperId: string,
|
||||
foreignDataWrapperType: RemoteServerType,
|
||||
foreignDataWrapperOptions: ForeignDataWrapperOptions<RemoteServerType>,
|
||||
) {
|
||||
const [name, options] = this.buildNameAndOptionsFromType(
|
||||
foreignDataWrapperType,
|
||||
foreignDataWrapperOptions,
|
||||
);
|
||||
|
||||
return `CREATE SERVER "${foreignDataWrapperId}" FOREIGN DATA WRAPPER ${name} OPTIONS (${options})`;
|
||||
}
|
||||
|
||||
updateForeignDataWrapper({
|
||||
foreignDataWrapperId,
|
||||
foreignDataWrapperOptions,
|
||||
}: {
|
||||
foreignDataWrapperId: string;
|
||||
foreignDataWrapperOptions: Partial<
|
||||
ForeignDataWrapperOptions<RemoteServerType>
|
||||
>;
|
||||
}) {
|
||||
const options = this.buildUpdateOptions(foreignDataWrapperOptions);
|
||||
|
||||
return `ALTER SERVER "${foreignDataWrapperId}" OPTIONS (${options})`;
|
||||
}
|
||||
|
||||
createUserMapping(
|
||||
foreignDataWrapperId: string,
|
||||
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 `CREATE USER MAPPING IF NOT EXISTS FOR CURRENT_USER SERVER "${foreignDataWrapperId}" OPTIONS (user '${userMappingOptions.username}', password '${userMappingOptions.password}')`;
|
||||
}
|
||||
|
||||
updateUserMapping(
|
||||
foreignDataWrapperId: string,
|
||||
userMappingOptions: Partial<UserMappingOptions>,
|
||||
) {
|
||||
const options = this.buildUpdateUserMappingOptions(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 (${options})`;
|
||||
}
|
||||
|
||||
private buildNameAndOptionsFromType(
|
||||
type: RemoteServerType,
|
||||
options: ForeignDataWrapperOptions<RemoteServerType>,
|
||||
) {
|
||||
switch (type) {
|
||||
case RemoteServerType.POSTGRES_FDW:
|
||||
return ['postgres_fdw', this.buildPostgresFDWQueryOptions(options)];
|
||||
default:
|
||||
throw new Error('Foreign data wrapper type not supported');
|
||||
}
|
||||
}
|
||||
|
||||
private buildUpdateOptions(
|
||||
options: Partial<ForeignDataWrapperOptions<RemoteServerType>>,
|
||||
) {
|
||||
const rawQuerySetStatements: string[] = [];
|
||||
|
||||
Object.entries(options).forEach(([key, value]) => {
|
||||
if (isDefined(value)) {
|
||||
rawQuerySetStatements.push(`SET ${key} '${value}'`);
|
||||
}
|
||||
});
|
||||
|
||||
return rawQuerySetStatements.join(', ');
|
||||
}
|
||||
|
||||
private buildUpdateUserMappingOptions(
|
||||
userMappingOptions?: Partial<UserMappingOptions>,
|
||||
) {
|
||||
const setStatements: string[] = [];
|
||||
|
||||
if (isDefined(userMappingOptions?.username)) {
|
||||
setStatements.push(`SET user '${userMappingOptions?.username}'`);
|
||||
}
|
||||
|
||||
if (isDefined(userMappingOptions?.password)) {
|
||||
setStatements.push(`SET password '${userMappingOptions?.password}'`);
|
||||
}
|
||||
|
||||
return setStatements.join(', ');
|
||||
}
|
||||
|
||||
private buildPostgresFDWQueryOptions(
|
||||
foreignDataWrapperOptions: ForeignDataWrapperOptions<RemoteServerType>,
|
||||
) {
|
||||
return `dbname '${foreignDataWrapperOptions.dbname}', host '${foreignDataWrapperOptions.host}', port '${foreignDataWrapperOptions.port}'`;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import {
|
||||
ForeignDataWrapperOptions,
|
||||
RemoteServerType,
|
||||
} from 'src/engine/metadata-modules/remote-server/remote-server.entity';
|
||||
import { UserMappingOptions } from 'src/engine/metadata-modules/remote-server/types/user-mapping-options';
|
||||
|
||||
@Injectable()
|
||||
export class ForeignDataWrapperServerQueryFactory {
|
||||
createForeignDataWrapperServer(
|
||||
foreignDataWrapperId: string,
|
||||
foreignDataWrapperType: RemoteServerType,
|
||||
foreignDataWrapperOptions: ForeignDataWrapperOptions<RemoteServerType>,
|
||||
) {
|
||||
const options = this.buildQueryOptions(foreignDataWrapperOptions, false);
|
||||
|
||||
return `CREATE SERVER "${foreignDataWrapperId}" FOREIGN DATA WRAPPER ${foreignDataWrapperType} OPTIONS (${options})`;
|
||||
}
|
||||
|
||||
updateForeignDataWrapperServer({
|
||||
foreignDataWrapperId,
|
||||
foreignDataWrapperOptions,
|
||||
}: {
|
||||
foreignDataWrapperId: string;
|
||||
foreignDataWrapperOptions: Partial<
|
||||
ForeignDataWrapperOptions<RemoteServerType>
|
||||
>;
|
||||
}) {
|
||||
const options = this.buildQueryOptions(foreignDataWrapperOptions, true);
|
||||
|
||||
return `ALTER SERVER "${foreignDataWrapperId}" OPTIONS (${options})`;
|
||||
}
|
||||
|
||||
createUserMapping(
|
||||
foreignDataWrapperId: string,
|
||||
userMappingOptions: UserMappingOptions,
|
||||
) {
|
||||
const options = this.buildQueryOptions(userMappingOptions, false);
|
||||
|
||||
// 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 `CREATE USER MAPPING IF NOT EXISTS FOR CURRENT_USER SERVER "${foreignDataWrapperId}" OPTIONS (${options})`;
|
||||
}
|
||||
|
||||
updateUserMapping(
|
||||
foreignDataWrapperId: string,
|
||||
userMappingOptions: Partial<UserMappingOptions>,
|
||||
) {
|
||||
const options = this.buildQueryOptions(userMappingOptions, true);
|
||||
|
||||
// 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 (${options})`;
|
||||
}
|
||||
|
||||
private buildQueryOptions(
|
||||
options:
|
||||
| ForeignDataWrapperOptions<RemoteServerType>
|
||||
| Partial<ForeignDataWrapperOptions<RemoteServerType>>
|
||||
| UserMappingOptions
|
||||
| Partial<UserMappingOptions>,
|
||||
isUpdate: boolean,
|
||||
) {
|
||||
const prefix = isUpdate ? 'SET ' : '';
|
||||
|
||||
return Object.entries(options)
|
||||
.map(([key, value]) => `${prefix}${key} '${value}'`)
|
||||
.join(', ');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user