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:
Thomas Trompette 2024-05-02 17:13:15 +02:00 committed by GitHub
parent 5128ea3ffb
commit f9c19c839b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 396 additions and 283 deletions

View File

@ -13,7 +13,7 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/
* Therefore it is highly recommended to use the babel or swc plugin for production.
*/
const documents = {
"\n fragment RemoteServerFields on RemoteServer {\n id\n createdAt\n foreignDataWrapperId\n foreignDataWrapperOptions\n foreignDataWrapperType\n userMappingOptions {\n username\n }\n updatedAt\n schema\n }\n": types.RemoteServerFieldsFragmentDoc,
"\n fragment RemoteServerFields on RemoteServer {\n id\n createdAt\n foreignDataWrapperId\n foreignDataWrapperOptions\n foreignDataWrapperType\n userMappingOptions {\n user\n }\n updatedAt\n schema\n }\n": types.RemoteServerFieldsFragmentDoc,
"\n fragment RemoteTableFields on RemoteTable {\n id\n name\n schema\n status\n }\n": types.RemoteTableFieldsFragmentDoc,
"\n \n mutation createServer($input: CreateRemoteServerInput!) {\n createOneRemoteServer(input: $input) {\n ...RemoteServerFields\n }\n }\n": types.CreateServerDocument,
"\n mutation deleteServer($input: RemoteServerIdInput!) {\n deleteOneRemoteServer(input: $input) {\n id\n }\n }\n": types.DeleteServerDocument,
@ -50,7 +50,7 @@ export function graphql(source: string): unknown;
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n fragment RemoteServerFields on RemoteServer {\n id\n createdAt\n foreignDataWrapperId\n foreignDataWrapperOptions\n foreignDataWrapperType\n userMappingOptions {\n username\n }\n updatedAt\n schema\n }\n"): (typeof documents)["\n fragment RemoteServerFields on RemoteServer {\n id\n createdAt\n foreignDataWrapperId\n foreignDataWrapperOptions\n foreignDataWrapperType\n userMappingOptions {\n username\n }\n updatedAt\n schema\n }\n"];
export function graphql(source: "\n fragment RemoteServerFields on RemoteServer {\n id\n createdAt\n foreignDataWrapperId\n foreignDataWrapperOptions\n foreignDataWrapperType\n userMappingOptions {\n user\n }\n updatedAt\n schema\n }\n"): (typeof documents)["\n fragment RemoteServerFields on RemoteServer {\n id\n createdAt\n foreignDataWrapperId\n foreignDataWrapperOptions\n foreignDataWrapperType\n userMappingOptions {\n user\n }\n updatedAt\n schema\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/

View File

@ -799,7 +799,7 @@ export type RemoteServer = {
id: Scalars['ID']['output'];
schema?: Maybe<Scalars['String']['output']>;
updatedAt: Scalars['DateTime']['output'];
userMappingOptions?: Maybe<UserMappingOptionsUsername>;
userMappingOptions?: Maybe<UserMappingOptionsUser>;
};
export type RemoteServerIdInput = {
@ -815,7 +815,7 @@ export type RemoteTable = {
__typename?: 'RemoteTable';
id?: Maybe<Scalars['UUID']['output']>;
name: Scalars['String']['output'];
schema: Scalars['String']['output'];
schema?: Maybe<Scalars['String']['output']>;
status: RemoteTableStatus;
};
@ -1057,17 +1057,17 @@ export type UserExists = {
export type UserMappingOptions = {
password?: InputMaybe<Scalars['String']['input']>;
username?: InputMaybe<Scalars['String']['input']>;
user?: InputMaybe<Scalars['String']['input']>;
};
export type UserMappingOptionsUpdateInput = {
password?: InputMaybe<Scalars['String']['input']>;
username?: InputMaybe<Scalars['String']['input']>;
user?: InputMaybe<Scalars['String']['input']>;
};
export type UserMappingOptionsUsername = {
__typename?: 'UserMappingOptionsUsername';
username?: Maybe<Scalars['String']['output']>;
export type UserMappingOptionsUser = {
__typename?: 'UserMappingOptionsUser';
user?: Maybe<Scalars['String']['output']>;
};
export type UserWorkspace = {
@ -1253,16 +1253,16 @@ export type RelationEdge = {
node: Relation;
};
export type RemoteServerFieldsFragment = { __typename?: 'RemoteServer', id: string, createdAt: any, foreignDataWrapperId: string, foreignDataWrapperOptions?: any | null, foreignDataWrapperType: string, updatedAt: any, schema?: string | null, userMappingOptions?: { __typename?: 'UserMappingOptionsUsername', username?: string | null } | null };
export type RemoteServerFieldsFragment = { __typename?: 'RemoteServer', id: string, createdAt: any, foreignDataWrapperId: string, foreignDataWrapperOptions?: any | null, foreignDataWrapperType: string, updatedAt: any, schema?: string | null, userMappingOptions?: { __typename?: 'UserMappingOptionsUser', user?: string | null } | null };
export type RemoteTableFieldsFragment = { __typename?: 'RemoteTable', id?: any | null, name: string, schema: string, status: RemoteTableStatus };
export type RemoteTableFieldsFragment = { __typename?: 'RemoteTable', id?: any | null, name: string, schema?: string | null, status: RemoteTableStatus };
export type CreateServerMutationVariables = Exact<{
input: CreateRemoteServerInput;
}>;
export type CreateServerMutation = { __typename?: 'Mutation', createOneRemoteServer: { __typename?: 'RemoteServer', id: string, createdAt: any, foreignDataWrapperId: string, foreignDataWrapperOptions?: any | null, foreignDataWrapperType: string, updatedAt: any, schema?: string | null, userMappingOptions?: { __typename?: 'UserMappingOptionsUsername', username?: string | null } | null } };
export type CreateServerMutation = { __typename?: 'Mutation', createOneRemoteServer: { __typename?: 'RemoteServer', id: string, createdAt: any, foreignDataWrapperId: string, foreignDataWrapperOptions?: any | null, foreignDataWrapperType: string, updatedAt: any, schema?: string | null, userMappingOptions?: { __typename?: 'UserMappingOptionsUser', user?: string | null } | null } };
export type DeleteServerMutationVariables = Exact<{
input: RemoteServerIdInput;
@ -1276,42 +1276,42 @@ export type SyncRemoteTableMutationVariables = Exact<{
}>;
export type SyncRemoteTableMutation = { __typename?: 'Mutation', syncRemoteTable: { __typename?: 'RemoteTable', id?: any | null, name: string, schema: string, status: RemoteTableStatus } };
export type SyncRemoteTableMutation = { __typename?: 'Mutation', syncRemoteTable: { __typename?: 'RemoteTable', id?: any | null, name: string, schema?: string | null, status: RemoteTableStatus } };
export type UnsyncRemoteTableMutationVariables = Exact<{
input: RemoteTableInput;
}>;
export type UnsyncRemoteTableMutation = { __typename?: 'Mutation', unsyncRemoteTable: { __typename?: 'RemoteTable', id?: any | null, name: string, schema: string, status: RemoteTableStatus } };
export type UnsyncRemoteTableMutation = { __typename?: 'Mutation', unsyncRemoteTable: { __typename?: 'RemoteTable', id?: any | null, name: string, schema?: string | null, status: RemoteTableStatus } };
export type UpdateServerMutationVariables = Exact<{
input: UpdateRemoteServerInput;
}>;
export type UpdateServerMutation = { __typename?: 'Mutation', updateOneRemoteServer: { __typename?: 'RemoteServer', id: string, createdAt: any, foreignDataWrapperId: string, foreignDataWrapperOptions?: any | null, foreignDataWrapperType: string, updatedAt: any, schema?: string | null, userMappingOptions?: { __typename?: 'UserMappingOptionsUsername', username?: string | null } | null } };
export type UpdateServerMutation = { __typename?: 'Mutation', updateOneRemoteServer: { __typename?: 'RemoteServer', id: string, createdAt: any, foreignDataWrapperId: string, foreignDataWrapperOptions?: any | null, foreignDataWrapperType: string, updatedAt: any, schema?: string | null, userMappingOptions?: { __typename?: 'UserMappingOptionsUser', user?: string | null } | null } };
export type GetManyDatabaseConnectionsQueryVariables = Exact<{
input: RemoteServerTypeInput;
}>;
export type GetManyDatabaseConnectionsQuery = { __typename?: 'Query', findManyRemoteServersByType: Array<{ __typename?: 'RemoteServer', id: string, createdAt: any, foreignDataWrapperId: string, foreignDataWrapperOptions?: any | null, foreignDataWrapperType: string, updatedAt: any, schema?: string | null, userMappingOptions?: { __typename?: 'UserMappingOptionsUsername', username?: string | null } | null }> };
export type GetManyDatabaseConnectionsQuery = { __typename?: 'Query', findManyRemoteServersByType: Array<{ __typename?: 'RemoteServer', id: string, createdAt: any, foreignDataWrapperId: string, foreignDataWrapperOptions?: any | null, foreignDataWrapperType: string, updatedAt: any, schema?: string | null, userMappingOptions?: { __typename?: 'UserMappingOptionsUser', user?: string | null } | null }> };
export type GetManyRemoteTablesQueryVariables = Exact<{
input: RemoteServerIdInput;
}>;
export type GetManyRemoteTablesQuery = { __typename?: 'Query', findAvailableRemoteTablesByServerId: Array<{ __typename?: 'RemoteTable', id?: any | null, name: string, schema: string, status: RemoteTableStatus }> };
export type GetManyRemoteTablesQuery = { __typename?: 'Query', findAvailableRemoteTablesByServerId: Array<{ __typename?: 'RemoteTable', id?: any | null, name: string, schema?: string | null, status: RemoteTableStatus }> };
export type GetOneDatabaseConnectionQueryVariables = Exact<{
input: RemoteServerIdInput;
}>;
export type GetOneDatabaseConnectionQuery = { __typename?: 'Query', findOneRemoteServerById: { __typename?: 'RemoteServer', id: string, createdAt: any, foreignDataWrapperId: string, foreignDataWrapperOptions?: any | null, foreignDataWrapperType: string, updatedAt: any, schema?: string | null, userMappingOptions?: { __typename?: 'UserMappingOptionsUsername', username?: string | null } | null } };
export type GetOneDatabaseConnectionQuery = { __typename?: 'Query', findOneRemoteServerById: { __typename?: 'RemoteServer', id: string, createdAt: any, foreignDataWrapperId: string, foreignDataWrapperOptions?: any | null, foreignDataWrapperType: string, updatedAt: any, schema?: string | null, userMappingOptions?: { __typename?: 'UserMappingOptionsUser', user?: string | null } | null } };
export type CreateOneObjectMetadataItemMutationVariables = Exact<{
input: CreateOneObjectInput;
@ -1372,16 +1372,16 @@ export type ObjectMetadataItemsQueryVariables = Exact<{
export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', edges: Array<{ __typename?: 'objectEdge', node: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, createdAt: any, updatedAt: any, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, fields: { __typename?: 'ObjectFieldsConnection', edges: Array<{ __typename?: 'fieldEdge', node: { __typename?: 'field', id: any, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isNullable?: boolean | null, createdAt: any, updatedAt: any, defaultValue?: any | null, options?: any | null, fromRelationMetadata?: { __typename?: 'relation', id: any, relationType: RelationMetadataType, toFieldMetadataId: string, toObjectMetadata: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, isSystem: boolean, isRemote: boolean } } | null, toRelationMetadata?: { __typename?: 'relation', id: any, relationType: RelationMetadataType, fromFieldMetadataId: string, fromObjectMetadata: { __typename?: 'object', id: any, dataSourceId: string, nameSingular: string, namePlural: string, isSystem: boolean, isRemote: boolean } } | null, relationDefinition?: { __typename?: 'RelationDefinition', direction: RelationDefinitionType, sourceObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'field', id: any, name: string }, targetObjectMetadata: { __typename?: 'object', id: any, nameSingular: string, namePlural: string }, targetFieldMetadata: { __typename?: 'field', id: any, name: string } } | null } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } };
export const RemoteServerFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteServerFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperId"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperOptions"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperType"}},{"kind":"Field","name":{"kind":"Name","value":"userMappingOptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"schema"}}]}}]} as unknown as DocumentNode<RemoteServerFieldsFragment, unknown>;
export const RemoteServerFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteServerFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperId"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperOptions"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperType"}},{"kind":"Field","name":{"kind":"Name","value":"userMappingOptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"}}]}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"schema"}}]}}]} as unknown as DocumentNode<RemoteServerFieldsFragment, unknown>;
export const RemoteTableFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteTableFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteTable"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"schema"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]} as unknown as DocumentNode<RemoteTableFieldsFragment, unknown>;
export const CreateServerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"createServer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateRemoteServerInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOneRemoteServer"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RemoteServerFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteServerFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperId"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperOptions"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperType"}},{"kind":"Field","name":{"kind":"Name","value":"userMappingOptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"schema"}}]}}]} as unknown as DocumentNode<CreateServerMutation, CreateServerMutationVariables>;
export const CreateServerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"createServer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateRemoteServerInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOneRemoteServer"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RemoteServerFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteServerFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperId"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperOptions"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperType"}},{"kind":"Field","name":{"kind":"Name","value":"userMappingOptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"}}]}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"schema"}}]}}]} as unknown as DocumentNode<CreateServerMutation, CreateServerMutationVariables>;
export const DeleteServerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"deleteServer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServerIdInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteOneRemoteServer"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode<DeleteServerMutation, DeleteServerMutationVariables>;
export const SyncRemoteTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"syncRemoteTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteTableInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"syncRemoteTable"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RemoteTableFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteTableFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteTable"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"schema"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]} as unknown as DocumentNode<SyncRemoteTableMutation, SyncRemoteTableMutationVariables>;
export const UnsyncRemoteTableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"unsyncRemoteTable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteTableInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"unsyncRemoteTable"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RemoteTableFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteTableFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteTable"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"schema"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]} as unknown as DocumentNode<UnsyncRemoteTableMutation, UnsyncRemoteTableMutationVariables>;
export const UpdateServerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"updateServer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateRemoteServerInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateOneRemoteServer"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RemoteServerFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteServerFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperId"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperOptions"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperType"}},{"kind":"Field","name":{"kind":"Name","value":"userMappingOptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"schema"}}]}}]} as unknown as DocumentNode<UpdateServerMutation, UpdateServerMutationVariables>;
export const GetManyDatabaseConnectionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetManyDatabaseConnections"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServerTypeInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findManyRemoteServersByType"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RemoteServerFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteServerFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperId"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperOptions"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperType"}},{"kind":"Field","name":{"kind":"Name","value":"userMappingOptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"schema"}}]}}]} as unknown as DocumentNode<GetManyDatabaseConnectionsQuery, GetManyDatabaseConnectionsQueryVariables>;
export const UpdateServerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"updateServer"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateRemoteServerInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateOneRemoteServer"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RemoteServerFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteServerFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperId"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperOptions"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperType"}},{"kind":"Field","name":{"kind":"Name","value":"userMappingOptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"}}]}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"schema"}}]}}]} as unknown as DocumentNode<UpdateServerMutation, UpdateServerMutationVariables>;
export const GetManyDatabaseConnectionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetManyDatabaseConnections"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServerTypeInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findManyRemoteServersByType"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RemoteServerFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteServerFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperId"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperOptions"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperType"}},{"kind":"Field","name":{"kind":"Name","value":"userMappingOptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"}}]}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"schema"}}]}}]} as unknown as DocumentNode<GetManyDatabaseConnectionsQuery, GetManyDatabaseConnectionsQueryVariables>;
export const GetManyRemoteTablesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetManyRemoteTables"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServerIdInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findAvailableRemoteTablesByServerId"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RemoteTableFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteTableFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteTable"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"schema"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]} as unknown as DocumentNode<GetManyRemoteTablesQuery, GetManyRemoteTablesQueryVariables>;
export const GetOneDatabaseConnectionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOneDatabaseConnection"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServerIdInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findOneRemoteServerById"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RemoteServerFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteServerFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperId"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperOptions"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperType"}},{"kind":"Field","name":{"kind":"Name","value":"userMappingOptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"username"}}]}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"schema"}}]}}]} as unknown as DocumentNode<GetOneDatabaseConnectionQuery, GetOneDatabaseConnectionQueryVariables>;
export const GetOneDatabaseConnectionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetOneDatabaseConnection"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServerIdInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findOneRemoteServerById"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"RemoteServerFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"RemoteServerFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"RemoteServer"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperId"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperOptions"}},{"kind":"Field","name":{"kind":"Name","value":"foreignDataWrapperType"}},{"kind":"Field","name":{"kind":"Name","value":"userMappingOptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"}}]}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"schema"}}]}}]} as unknown as DocumentNode<GetOneDatabaseConnectionQuery, GetOneDatabaseConnectionQueryVariables>;
export const CreateOneObjectMetadataItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateOneObjectMetadataItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateOneObjectInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOneObject"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"dataSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"nameSingular"}},{"kind":"Field","name":{"kind":"Name","value":"namePlural"}},{"kind":"Field","name":{"kind":"Name","value":"labelSingular"}},{"kind":"Field","name":{"kind":"Name","value":"labelPlural"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"labelIdentifierFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"imageIdentifierFieldMetadataId"}}]}}]}}]} as unknown as DocumentNode<CreateOneObjectMetadataItemMutation, CreateOneObjectMetadataItemMutationVariables>;
export const CreateOneFieldMetadataItemDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateOneFieldMetadataItem"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateOneFieldMetadataInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOneField"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"isNullable"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"defaultValue"}},{"kind":"Field","name":{"kind":"Name","value":"options"}}]}}]}}]} as unknown as DocumentNode<CreateOneFieldMetadataItemMutation, CreateOneFieldMetadataItemMutationVariables>;
export const CreateOneRelationMetadataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateOneRelationMetadata"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateOneRelationInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOneRelation"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"relationType"}},{"kind":"Field","name":{"kind":"Name","value":"fromObjectMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"toObjectMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"fromFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"toFieldMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<CreateOneRelationMetadataMutation, CreateOneRelationMetadataMutationVariables>;

View File

@ -577,14 +577,14 @@ export type RemoteServer = {
id: Scalars['ID'];
schema?: Maybe<Scalars['String']>;
updatedAt: Scalars['DateTime'];
userMappingOptions?: Maybe<UserMappingOptionsUsername>;
userMappingOptions?: Maybe<UserMappingOptionsUser>;
};
export type RemoteTable = {
__typename?: 'RemoteTable';
id?: Maybe<Scalars['UUID']>;
name: Scalars['String'];
schema: Scalars['String'];
schema?: Maybe<Scalars['String']>;
status: RemoteTableStatus;
};
@ -772,9 +772,9 @@ export type UserExists = {
exists: Scalars['Boolean'];
};
export type UserMappingOptionsUsername = {
__typename?: 'UserMappingOptionsUsername';
username?: Maybe<Scalars['String']>;
export type UserMappingOptionsUser = {
__typename?: 'UserMappingOptionsUser';
user?: Maybe<Scalars['String']>;
};
export type UserWorkspace = {

View File

@ -8,7 +8,7 @@ export const DATABASE_CONNECTION_FRAGMENT = gql`
foreignDataWrapperOptions
foreignDataWrapperType
userMappingOptions {
username
user
}
updatedAt
schema

View File

@ -8,7 +8,7 @@ export const settingsIntegrationPostgreSQLConnectionFormSchema = z.object({
dbname: z.string().min(1),
host: z.string().min(1),
port: z.preprocess((val) => parseInt(val as string), z.number().positive()),
username: z.string().min(1),
user: z.string().min(1),
password: z.string().min(1),
schema: z.string().min(1),
});
@ -52,9 +52,9 @@ export const SettingsIntegrationPostgreSQLConnectionForm = ({
{ name: 'host' as const, label: 'Host', placeholder: 'host' },
{ name: 'port' as const, label: 'Port', placeholder: '5432' },
{
name: 'username' as const,
label: 'Username',
placeholder: 'username',
name: 'user' as const,
label: 'User',
placeholder: 'user',
},
{
name: 'password' as const,

View File

@ -28,7 +28,7 @@ export const getFormDefaultValuesFromConnection = ({
dbname: connection.foreignDataWrapperOptions.dbname,
host: connection.foreignDataWrapperOptions.host,
port: connection.foreignDataWrapperOptions.port,
username: connection.userMappingOptions?.username || undefined,
user: connection.userMappingOptions?.user || undefined,
schema: connection.schema || undefined,
password: '',
};
@ -51,7 +51,7 @@ export const formatValuesForUpdate = ({
const formattedValues = {
userMappingOptions: pickBy(
{
username: formValues.username,
user: formValues.user,
password: formValues.password,
},
identity,

View File

@ -41,7 +41,7 @@ const createRemoteServerInputSchema = newConnectionSchema
},
userMappingOptions: {
password: values.password,
username: values.username,
user: values.user,
},
schema: values.schema,
}));

View File

@ -12,7 +12,7 @@ export const mockedRemoteServers = [
foreignDataWrapperType: 'postgres_fdw',
userMappingOptions: {
__typename: 'UserMappingOptionsDTO',
username: 'twenty',
user: 'twenty',
},
updatedAt: '2024-04-30T13:41:25.858Z',
schema: 'public',

View File

@ -45,6 +45,11 @@ export const seedFeatureFlags = async (
workspaceId: workspaceId,
value: true,
},
{
key: FeatureFlagKeys.IsStripeIntegrationEnabled,
workspaceId: workspaceId,
value: true,
},
])
.execute();
};

View File

@ -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,
];

View File

@ -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}'`;
}
}

View File

@ -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(', ');
}
}

View File

@ -21,6 +21,7 @@ export enum FeatureFlagKeys {
IsEventObjectEnabled = 'IS_EVENT_OBJECT_ENABLED',
IsAirtableIntegrationEnabled = 'IS_AIRTABLE_INTEGRATION_ENABLED',
IsPostgreSQLIntegrationEnabled = 'IS_POSTGRESQL_INTEGRATION_ENABLED',
IsStripeIntegrationEnabled = 'IS_STRIPE_INTEGRATION_ENABLED',
IsMultiSelectEnabled = 'IS_MULTI_SELECT_ENABLED',
}

View File

@ -7,7 +7,7 @@ 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';
import { UserMappingOptions } from 'src/engine/metadata-modules/remote-server/types/user-mapping-options';
@InputType()
export class CreateRemoteServerInput<T extends RemoteServerType> {

View File

@ -10,7 +10,7 @@ import {
import {
UserMappingOptions,
UserMappingOptionsUpdateInput,
} from 'src/engine/metadata-modules/remote-server/utils/user-mapping-options.utils';
} from 'src/engine/metadata-modules/remote-server/types/user-mapping-options';
@InputType()
export class UpdateRemoteServerInput<T extends RemoteServerType> {

View File

@ -2,9 +2,9 @@ import { ObjectType, Field } from '@nestjs/graphql';
import { IsOptional } from 'class-validator';
@ObjectType('UserMappingOptionsUsername')
@ObjectType('UserMappingOptionsUser')
export class UserMappingOptionsDTO {
@IsOptional()
@Field(() => String, { nullable: true })
username: string;
user: string;
}

View File

@ -10,11 +10,12 @@ import {
} from 'typeorm';
import { RemoteTableEntity } from 'src/engine/metadata-modules/remote-server/remote-table/remote-table.entity';
import { UserMappingOptions } from 'src/engine/metadata-modules/remote-server/utils/user-mapping-options.utils';
import { UserMappingOptions } from 'src/engine/metadata-modules/remote-server/types/user-mapping-options';
import { DistantTables } from 'src/engine/metadata-modules/remote-server/remote-table/distant-table/types/distant-table';
export enum RemoteServerType {
POSTGRES_FDW = 'postgres_fdw',
STRIPE_FDW = 'stripe_fdw',
}
type PostgresForeignDataWrapperOptions = {
@ -23,10 +24,17 @@ type PostgresForeignDataWrapperOptions = {
dbname: string;
};
type StripeForeignDataWrapperOptions = {
api_key: string;
};
export type ForeignDataWrapperOptions<T extends RemoteServerType> =
T extends RemoteServerType.POSTGRES_FDW
? PostgresForeignDataWrapperOptions
: never;
: T extends RemoteServerType.STRIPE_FDW
? StripeForeignDataWrapperOptions
: never;
@Entity('remoteServer')
export class RemoteServerEntity<T extends RemoteServerType> {
@PrimaryGeneratedColumn('uuid')

View File

@ -1,7 +1,7 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
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 { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { RemoteServerEntity } from 'src/engine/metadata-modules/remote-server/remote-server.entity';
import { RemoteServerResolver } from 'src/engine/metadata-modules/remote-server/remote-server.resolver';
@ -19,7 +19,7 @@ import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/works
providers: [
RemoteServerService,
RemoteServerResolver,
ForeignDataWrapperQueryFactory,
ForeignDataWrapperServerQueryFactory,
],
})
export class RemoteServerModule {}

View File

@ -20,11 +20,11 @@ import {
validateObjectAgainstInjections,
validateStringAgainstInjections,
} from 'src/engine/metadata-modules/remote-server/utils/validate-remote-server-input.utils';
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 { RemoteTableService } from 'src/engine/metadata-modules/remote-server/remote-table/remote-table.service';
import { UpdateRemoteServerInput } from 'src/engine/metadata-modules/remote-server/dtos/update-remote-server.input';
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { updateRemoteServerRawQuery } from 'src/engine/metadata-modules/remote-server/utils/build-update-remote-server-raw-query.utils';
import { buildUpdateRemoteServerRawQuery } from 'src/engine/metadata-modules/remote-server/utils/build-update-remote-server-raw-query.utils';
import { validateRemoteServerType } from 'src/engine/metadata-modules/remote-server/utils/validate-remote-server-type.util';
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
@ -38,7 +38,7 @@ export class RemoteServerService<T extends RemoteServerType> {
@InjectDataSource('metadata')
private readonly metadataDataSource: DataSource,
private readonly environmentService: EnvironmentService,
private readonly foreignDataWrapperQueryFactory: ForeignDataWrapperQueryFactory,
private readonly foreignDataWrapperServerQueryFactory: ForeignDataWrapperServerQueryFactory,
private readonly remoteTableService: RemoteTableService,
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
@InjectRepository(FeatureFlagEntity, 'core')
@ -85,7 +85,7 @@ export class RemoteServerService<T extends RemoteServerType> {
);
const foreignDataWrapperQuery =
this.foreignDataWrapperQueryFactory.createForeignDataWrapper(
this.foreignDataWrapperServerQueryFactory.createForeignDataWrapperServer(
createdRemoteServer.foreignDataWrapperId,
remoteServerInput.foreignDataWrapperType,
remoteServerInput.foreignDataWrapperOptions,
@ -95,7 +95,7 @@ export class RemoteServerService<T extends RemoteServerType> {
if (remoteServerInput.userMappingOptions) {
const userMappingQuery =
this.foreignDataWrapperQueryFactory.createUserMapping(
this.foreignDataWrapperServerQueryFactory.createUserMapping(
createdRemoteServer.foreignDataWrapperId,
remoteServerInput.userMappingOptions,
);
@ -167,18 +167,20 @@ export class RemoteServerService<T extends RemoteServerType> {
!isEmpty(partialRemoteServerWithUpdates.foreignDataWrapperOptions)
) {
const foreignDataWrapperQuery =
this.foreignDataWrapperQueryFactory.updateForeignDataWrapper({
foreignDataWrapperId,
foreignDataWrapperOptions:
partialRemoteServerWithUpdates.foreignDataWrapperOptions,
});
this.foreignDataWrapperServerQueryFactory.updateForeignDataWrapperServer(
{
foreignDataWrapperId,
foreignDataWrapperOptions:
partialRemoteServerWithUpdates.foreignDataWrapperOptions,
},
);
await entityManager.query(foreignDataWrapperQuery);
}
if (!isEmpty(partialRemoteServerWithUpdates.userMappingOptions)) {
const userMappingQuery =
this.foreignDataWrapperQueryFactory.updateUserMapping(
this.foreignDataWrapperServerQueryFactory.updateUserMapping(
foreignDataWrapperId,
partialRemoteServerWithUpdates.userMappingOptions,
);
@ -254,7 +256,7 @@ export class RemoteServerService<T extends RemoteServerType> {
Pick<RemoteServerEntity<RemoteServerType>, 'workspaceId' | 'id'>,
): Promise<RemoteServerEntity<RemoteServerType>> {
const [parameters, rawQuery] =
updateRemoteServerRawQuery(remoteServerToUpdate);
buildUpdateRemoteServerRawQuery(remoteServerToUpdate);
const updateResult = await this.workspaceDataSourceService.executeRawQuery(
rawQuery,

View File

@ -11,6 +11,7 @@ import {
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
import { DistantTableColumn } from 'src/engine/metadata-modules/remote-server/remote-table/distant-table/types/distant-table-column';
import { DistantTables } from 'src/engine/metadata-modules/remote-server/remote-table/distant-table/types/distant-table';
import { STRIPE_DISTANT_TABLES } from 'src/engine/metadata-modules/remote-server/remote-table/distant-table/util/stripe-distant-tables.util';
@Injectable()
export class DistantTableService {
@ -27,7 +28,9 @@ export class DistantTableService {
tableName: string,
): Promise<DistantTableColumn[]> {
if (!remoteServer.availableTables) {
throw new Error('Remote server available tables are not defined');
throw new BadRequestException(
'Remote server available tables are not defined',
);
}
return remoteServer.availableTables[tableName];
@ -47,6 +50,20 @@ export class DistantTableService {
private async createAvailableTables(
remoteServer: RemoteServerEntity<RemoteServerType>,
workspaceId: string,
): Promise<DistantTables> {
if (remoteServer.schema) {
return this.createAvailableTablesFromDynamicSchema(
remoteServer,
workspaceId,
);
}
return this.createAvailableTablesFromStaticSchema(remoteServer);
}
private async createAvailableTablesFromDynamicSchema(
remoteServer: RemoteServerEntity<RemoteServerType>,
workspaceId: string,
): Promise<DistantTables> {
if (!remoteServer.schema) {
throw new BadRequestException('Remote server schema is not defined');
@ -99,4 +116,21 @@ export class DistantTableService {
return availableTables;
}
private async createAvailableTablesFromStaticSchema(
remoteServer: RemoteServerEntity<RemoteServerType>,
): Promise<DistantTables> {
switch (remoteServer.foreignDataWrapperType) {
case RemoteServerType.STRIPE_FDW:
this.remoteServerRepository.update(remoteServer.id, {
availableTables: STRIPE_DISTANT_TABLES,
});
return STRIPE_DISTANT_TABLES;
default:
throw new BadRequestException(
`Type ${remoteServer.foreignDataWrapperType} does not have a static schema.`,
);
}
}
}

View File

@ -0,0 +1,91 @@
import { DistantTables } from 'src/engine/metadata-modules/remote-server/remote-table/distant-table/types/distant-table';
export const STRIPE_DISTANT_TABLES: DistantTables = {
balance_transactions: [
{ columnName: 'id', dataType: 'text', udtName: 'text' },
{ columnName: 'amount', dataType: 'bigint', udtName: 'int8' },
{ columnName: 'currency', dataType: 'text', udtName: 'text' },
{ columnName: 'description', dataType: 'text', udtName: 'text' },
{ columnName: 'fee', dataType: 'bigint', udtName: 'int8' },
{ columnName: 'net', dataType: 'bigint', udtName: 'int8' },
{ columnName: 'status', dataType: 'text', udtName: 'text' },
{ columnName: 'type', dataType: 'text', udtName: 'text' },
{ columnName: 'created', dataType: 'timestamp', udtName: 'timestamp' },
],
customers: [
{ columnName: 'id', dataType: 'text', udtName: 'text' },
{ columnName: 'email', dataType: 'text', udtName: 'text' },
{ columnName: 'name', dataType: 'text', udtName: 'text' },
{ columnName: 'description', dataType: 'text', udtName: 'text' },
{ columnName: 'created', dataType: 'timestamp', udtName: 'timestamp' },
],
disputes: [
{ columnName: 'id', dataType: 'text', udtName: 'text' },
{ columnName: 'amount', dataType: 'bigint', udtName: 'int8' },
{ columnName: 'currency', dataType: 'text', udtName: 'text' },
{ columnName: 'charge', dataType: 'text', udtName: 'text' },
{ columnName: 'payment_intent', dataType: 'text', udtName: 'text' },
{ columnName: 'reason', dataType: 'text', udtName: 'text' },
{ columnName: 'status', dataType: 'text', udtName: 'text' },
{ columnName: 'created', dataType: 'timestamp', udtName: 'timestamp' },
],
files: [
{ columnName: 'id', dataType: 'text', udtName: 'text' },
{ columnName: 'filename', dataType: 'text', udtName: 'text' },
{ columnName: 'purpose', dataType: 'text', udtName: 'text' },
{ columnName: 'title', dataType: 'text', udtName: 'text' },
{ columnName: 'size', dataType: 'bigint', udtName: 'int8' },
{ columnName: 'type', dataType: 'text', udtName: 'text' },
{ columnName: 'url', dataType: 'text', udtName: 'text' },
{ columnName: 'created', dataType: 'timestamp', udtName: 'timestamp' },
{ columnName: 'expires_at', dataType: 'timestamp', udtName: 'timestamp' },
],
file_links: [
{ columnName: 'id', dataType: 'text', udtName: 'text' },
{ columnName: 'file', dataType: 'text', udtName: 'text' },
{ columnName: 'url', dataType: 'text', udtName: 'text' },
{ columnName: 'created', dataType: 'timestamp', udtName: 'timestamp' },
{ columnName: 'expired', dataType: 'bool', udtName: 'boolean' },
{ columnName: 'expires_at', dataType: 'timestamp', udtName: 'timestamp' },
],
mandates: [
{ columnName: 'id', dataType: 'text', udtName: 'text' },
{ columnName: 'payment_method', dataType: 'text', udtName: 'text' },
{ columnName: 'status', dataType: 'text', udtName: 'text' },
{ columnName: 'type', dataType: 'text', udtName: 'text' },
],
payouts: [
{ columnName: 'id', dataType: 'text', udtName: 'text' },
{ columnName: 'amount', dataType: 'bigint', udtName: 'int8' },
{ columnName: 'currency', dataType: 'text', udtName: 'text' },
{ columnName: 'description', dataType: 'text', udtName: 'text' },
{ columnName: 'status', dataType: 'text', udtName: 'text' },
{ columnName: 'created', dataType: 'timestamp', udtName: 'timestamp' },
],
refunds: [
{ columnName: 'id', dataType: 'text', udtName: 'text' },
{ columnName: 'amount', dataType: 'bigint', udtName: 'int8' },
{ columnName: 'currency', dataType: 'text', udtName: 'text' },
{ columnName: 'charge', dataType: 'text', udtName: 'text' },
{ columnName: 'payment_intent', dataType: 'text', udtName: 'text' },
{ columnName: 'reason', dataType: 'text', udtName: 'text' },
{ columnName: 'status', dataType: 'text', udtName: 'text' },
{ columnName: 'created', dataType: 'timestamp', udtName: 'timestamp' },
],
topups: [
{ columnName: 'id', dataType: 'text', udtName: 'text' },
{ columnName: 'amount', dataType: 'bigint', udtName: 'int8' },
{ columnName: 'currency', dataType: 'text', udtName: 'text' },
{ columnName: 'description', dataType: 'text', udtName: 'text' },
{ columnName: 'status', dataType: 'text', udtName: 'text' },
{ columnName: 'created', dataType: 'timestamp', udtName: 'timestamp' },
],
transfers: [
{ columnName: 'id', dataType: 'text', udtName: 'text' },
{ columnName: 'amount', dataType: 'bigint', udtName: 'int8' },
{ columnName: 'currency', dataType: 'text', udtName: 'text' },
{ columnName: 'description', dataType: 'text', udtName: 'text' },
{ columnName: 'destination', dataType: 'text', udtName: 'text' },
{ columnName: 'created', dataType: 'timestamp', udtName: 'timestamp' },
],
};

View File

@ -1,7 +1,7 @@
import { ObjectType, Field, registerEnumType } from '@nestjs/graphql';
import { IDField } from '@ptc-org/nestjs-query-graphql';
import { IsEnum } from 'class-validator';
import { IsEnum, IsOptional } from 'class-validator';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
@ -27,6 +27,7 @@ export class RemoteTableDTO {
@Field(() => RemoteTableStatus)
status: RemoteTableStatus;
@Field(() => String)
@IsOptional()
@Field(() => String, { nullable: true })
schema?: string;
}

View File

@ -26,6 +26,7 @@ import { WorkspaceMigrationService } from 'src/engine/metadata-modules/workspace
import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service';
import { generateMigrationName } from 'src/engine/metadata-modules/workspace-migration/utils/generate-migration-name.util';
import {
ReferencedTable,
WorkspaceMigrationForeignColumnDefinition,
WorkspaceMigrationForeignTable,
WorkspaceMigrationTableActionType,
@ -338,6 +339,11 @@ export class RemoteTableService {
remoteServer: RemoteServerEntity<RemoteServerType>,
distantTableColumns: DistantTableColumn[],
) {
const referencedTable: ReferencedTable = this.buildReferencedTable(
remoteServer,
remoteTableInput,
);
const workspaceMigration =
await this.workspaceMigrationService.createCustomMigration(
generateMigrationName(`create-foreign-table-${localTableName}`),
@ -355,8 +361,7 @@ export class RemoteTableService {
distantColumnName: column.columnName,
}) satisfies WorkspaceMigrationForeignColumnDefinition,
),
referencedTableName: remoteTableInput.name,
referencedTableSchema: remoteServer.schema,
referencedTable,
foreignDataWrapperId: remoteServer.foreignDataWrapperId,
} satisfies WorkspaceMigrationForeignTable,
},
@ -430,4 +435,21 @@ export class RemoteTableService {
}
}
}
private buildReferencedTable(
remoteServer: RemoteServerEntity<RemoteServerType>,
remoteTableInput: RemoteTableInput,
): ReferencedTable {
switch (remoteServer.foreignDataWrapperType) {
case RemoteServerType.POSTGRES_FDW:
return {
table_name: remoteTableInput.name,
schema_name: remoteServer.schema,
};
case RemoteServerType.STRIPE_FDW:
return { object: remoteTableInput.name };
default:
throw new BadRequestException('Foreign data wrapper not supported');
}
}
}

View File

@ -7,6 +7,9 @@ export const mapUdtNameToFieldType = (udtName: string): FieldMetadataType => {
case 'uuid':
return FieldMetadataType.UUID;
case 'varchar':
case 'text':
case 'bigint':
case 'int8':
return FieldMetadataType.TEXT;
case 'bool':
return FieldMetadataType.BOOLEAN;

View File

@ -7,7 +7,7 @@ import { IsOptional } from 'class-validator';
export class UserMappingOptions {
@IsOptional()
@Field(() => String, { nullable: true })
username: string;
user: string;
@IsOptional()
@Field(() => String, { nullable: true })
@ -18,7 +18,7 @@ export class UserMappingOptions {
export class UserMappingOptionsUpdateInput {
@IsOptional()
@Field(() => String, { nullable: true })
username?: string;
user?: string;
@IsOptional()
@Field(() => String, { nullable: true })

View File

@ -1,135 +1,43 @@
import { BadRequestException } from '@nestjs/common';
import { isDefined } from 'class-validator';
import {
ForeignDataWrapperOptions,
RemoteServerEntity,
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';
import { UserMappingOptions } from 'src/engine/metadata-modules/remote-server/types/user-mapping-options';
export type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>;
};
const buildUserMappingOptionsQuery = (
parameters: any[],
parametersPositions: object,
userMappingOptions: DeepPartial<UserMappingOptions>,
): string | null => {
const shouldUpdateUserMappingOptionsPassword = isDefined(
userMappingOptions?.password,
);
if (shouldUpdateUserMappingOptionsPassword) {
parameters.push(userMappingOptions?.password);
parametersPositions['password'] = parameters.length;
}
const shouldUpdateUserMappingOptionsUsername = isDefined(
userMappingOptions?.username,
);
if (shouldUpdateUserMappingOptionsUsername) {
parameters.push(userMappingOptions?.username);
parametersPositions['username'] = parameters.length;
}
if (
shouldUpdateUserMappingOptionsPassword ||
shouldUpdateUserMappingOptionsUsername
) {
return `"userMappingOptions" = jsonb_set(${
shouldUpdateUserMappingOptionsPassword &&
shouldUpdateUserMappingOptionsUsername
? `jsonb_set(
"userMappingOptions",
'{username}',
to_jsonb($${parametersPositions['username']}::text)
),
'{password}',
to_jsonb($${parametersPositions['password']}::text)
`
: shouldUpdateUserMappingOptionsPassword
? `"userMappingOptions",
'{password}',
to_jsonb($${parametersPositions['password']}::text)
`
: `"userMappingOptions",
'{username}',
to_jsonb($${parametersPositions['username']}::text)
`
})`;
}
return null;
};
// TO DO This only works for postgres_fdw type for now, lets make it more generic when we have a different type
export const updateRemoteServerRawQuery = (
export const buildUpdateRemoteServerRawQuery = (
remoteServerToUpdate: DeepPartial<RemoteServerEntity<RemoteServerType>> &
Pick<RemoteServerEntity<RemoteServerType>, 'workspaceId' | 'id'>,
): [any[], string] => {
const parameters: any[] = [remoteServerToUpdate.id];
const parametersPositions = {};
const options: string[] = [];
const [parameters, parametersPositions] =
buildParametersAndPositions(remoteServerToUpdate);
if (remoteServerToUpdate.userMappingOptions) {
const userMappingOptionsQuery = buildUserMappingOptionsQuery(
parameters,
parametersPositions,
const userMappingOptionsQuery = buildJsonRawQuery(
remoteServerToUpdate.userMappingOptions,
parametersPositions,
'userMappingOptions',
);
if (userMappingOptionsQuery) options.push(userMappingOptionsQuery);
options.push(userMappingOptionsQuery);
}
const shouldUpdateFdwDbname = isDefined(
remoteServerToUpdate.foreignDataWrapperOptions?.dbname,
);
if (remoteServerToUpdate.foreignDataWrapperOptions) {
const foreignDataWrapperOptionsQuery = buildJsonRawQuery(
remoteServerToUpdate.foreignDataWrapperOptions,
parametersPositions,
'foreignDataWrapperOptions',
);
if (shouldUpdateFdwDbname) {
parameters.push(remoteServerToUpdate?.foreignDataWrapperOptions?.dbname);
parametersPositions['dbname'] = parameters.length;
}
const shouldUpdateFdwHost = isDefined(
remoteServerToUpdate.foreignDataWrapperOptions?.host,
);
if (shouldUpdateFdwHost) {
parameters.push(remoteServerToUpdate?.foreignDataWrapperOptions?.host);
parametersPositions['host'] = parameters.length;
}
const shouldUpdateFdwPort = isDefined(
remoteServerToUpdate.foreignDataWrapperOptions?.port,
);
if (shouldUpdateFdwPort) {
parameters.push(remoteServerToUpdate?.foreignDataWrapperOptions?.port);
parametersPositions['port'] = parameters.length;
}
if (shouldUpdateFdwDbname || shouldUpdateFdwHost || shouldUpdateFdwPort) {
const fwdOptionsQuery = `"foreignDataWrapperOptions" = jsonb_set(${
shouldUpdateFdwDbname && shouldUpdateFdwHost && shouldUpdateFdwPort
? `jsonb_set(jsonb_set("foreignDataWrapperOptions", '{dbname}', to_jsonb($${parametersPositions['dbname']}::text)), '{host}', to_jsonb($${parametersPositions['host']}::text)), '{port}', to_jsonb($${parametersPositions['port']}::text)`
: shouldUpdateFdwDbname && shouldUpdateFdwHost
? `jsonb_set("foreignDataWrapperOptions", '{dbname}', to_jsonb($${parametersPositions['dbname']}::text)), '{host}', to_jsonb($${parametersPositions['host']}::text)`
: shouldUpdateFdwDbname && shouldUpdateFdwPort
? `jsonb_set("foreignDataWrapperOptions", '{dbname}', to_jsonb($${parametersPositions['dbname']}::text)), '{port}', to_jsonb($${parametersPositions['port']}::text)`
: shouldUpdateFdwHost && shouldUpdateFdwPort
? `jsonb_set("foreignDataWrapperOptions", '{host}', to_jsonb($${parametersPositions['host']}::text)), '{port}', to_jsonb($${parametersPositions['port']}::text)`
: shouldUpdateFdwDbname
? `"foreignDataWrapperOptions", '{dbname}', to_jsonb($${parametersPositions['dbname']}::text)`
: shouldUpdateFdwHost
? `"foreignDataWrapperOptions", '{host}', to_jsonb($${parametersPositions['host']}::text)`
: `"foreignDataWrapperOptions", '{port}', to_jsonb($${parametersPositions['port']}::text)`
})`;
options.push(fwdOptionsQuery);
options.push(foreignDataWrapperOptionsQuery);
}
if (options.length < 1) {
@ -142,3 +50,57 @@ export const updateRemoteServerRawQuery = (
return [parameters, rawQuery];
};
const buildParametersAndPositions = (
remoteServerToUpdate: DeepPartial<RemoteServerEntity<RemoteServerType>> &
Pick<RemoteServerEntity<RemoteServerType>, 'workspaceId' | 'id'>,
): [any[], object] => {
const parameters: any[] = [remoteServerToUpdate.id];
const parametersPositions = {};
if (remoteServerToUpdate.userMappingOptions) {
Object.entries(remoteServerToUpdate.userMappingOptions).forEach(
([key, value]) => {
parameters.push(value);
parametersPositions[key] = parameters.length;
},
);
}
if (remoteServerToUpdate.foreignDataWrapperOptions) {
Object.entries(remoteServerToUpdate.foreignDataWrapperOptions).forEach(
([key, value]) => {
parameters.push(value);
parametersPositions[key] = parameters.length;
},
);
}
return [parameters, parametersPositions];
};
const buildJsonRawQuery = (
options:
| Partial<UserMappingOptions>
| Partial<ForeignDataWrapperOptions<RemoteServerType>>,
parametersPositions: object,
objectName: string,
): string => {
const buildJsonSet = (
opts:
| Partial<UserMappingOptions>
| Partial<ForeignDataWrapperOptions<RemoteServerType>>,
): string => {
const [[firstKey, _], ...followingOptions] = Object.entries(opts);
let query = `jsonb_set("${objectName}", '{${firstKey}}', to_jsonb($${parametersPositions[firstKey]}::text))`;
followingOptions.forEach(([key, _]) => {
query = `jsonb_set(${query}, '{${key}}', to_jsonb($${parametersPositions[key]}::text))`;
});
return query;
};
return `"${objectName}" = ${buildJsonSet(options)}`;
};

View File

@ -32,6 +32,8 @@ const getFeatureFlagKey = (remoteServerType: RemoteServerType) => {
switch (remoteServerType) {
case RemoteServerType.POSTGRES_FDW:
return FeatureFlagKeys.IsPostgreSQLIntegrationEnabled;
case RemoteServerType.STRIPE_FDW:
return FeatureFlagKeys.IsStripeIntegrationEnabled;
default:
throw new BadRequestException(
`Type ${remoteServerType} is not supported.`,

View File

@ -67,10 +67,20 @@ export type WorkspaceMigrationForeignColumnDefinition =
distantColumnName: string;
};
type ReferencedObject = {
object: string;
};
type ReferencedTableWithSchema = {
table_name: string;
schema_name: string;
};
export type ReferencedTable = ReferencedObject | ReferencedTableWithSchema;
export type WorkspaceMigrationForeignTable = {
columns: WorkspaceMigrationForeignColumnDefinition[];
referencedTableName: string;
referencedTableSchema: string;
referencedTable: ReferencedObject | ReferencedTableWithSchema;
foreignDataWrapperId: string;
};

View File

@ -495,8 +495,14 @@ export class WorkspaceMigrationRunnerService {
)
.join(', ');
let serverOptions = '';
Object.entries(foreignTable.referencedTable).forEach(([key, value]) => {
serverOptions += ` ${key} '${value}'`;
});
await queryRunner.query(
`CREATE FOREIGN TABLE ${schemaName}."${name}" (${foreignTableColumns}) SERVER "${foreignTable.foreignDataWrapperId}" OPTIONS (schema_name '${foreignTable.referencedTableSchema}', table_name '${foreignTable.referencedTableName}')`,
`CREATE FOREIGN TABLE ${schemaName}."${name}" (${foreignTableColumns}) SERVER "${foreignTable.foreignDataWrapperId}" OPTIONS (${serverOptions})`,
);
await queryRunner.query(`

View File

@ -59,6 +59,7 @@ export class AddStandardIdCommand extends CommandRunner {
IS_AIRTABLE_INTEGRATION_ENABLED: true,
IS_POSTGRESQL_INTEGRATION_ENABLED: true,
IS_MULTI_SELECT_ENABLED: false,
IS_STRIPE_INTEGRATION_ENABLED: false,
},
);
const standardFieldMetadataCollection = this.standardFieldFactory.create(
@ -74,6 +75,7 @@ export class AddStandardIdCommand extends CommandRunner {
IS_AIRTABLE_INTEGRATION_ENABLED: true,
IS_POSTGRESQL_INTEGRATION_ENABLED: true,
IS_MULTI_SELECT_ENABLED: false,
IS_STRIPE_INTEGRATION_ENABLED: false,
},
);