diff --git a/packages/backend/src/apps/postgres/actions/delete/index.ts b/packages/backend/src/apps/postgres/actions/delete/index.ts new file mode 100644 index 00000000..60e1112f --- /dev/null +++ b/packages/backend/src/apps/postgres/actions/delete/index.ts @@ -0,0 +1,85 @@ +import { IJSONObject, IJSONArray } from '@automatisch/types'; +import defineAction from '../../../../helpers/define-action'; +import setConfig from '../../common/postgres-configuration'; +import setParams from '../../common/set-run-time-parameters'; + +export default defineAction({ + name: 'Delete', + key: 'delete', + description: 'Cteate new item in a table in specific schema in postgreSQL.', + arguments: [ + { + label: 'Schema name', + key: 'schema', + type: 'string' as const, + value: 'public', + required: true, + description: 'The name of the schema.', + variables: false, + }, + { + label: 'Table name', + key: 'table', + type: 'string' as const, + required: true, + description: 'The name of the table.', + variables: false, + }, + { + label: 'Where statement', + key: 'whereStatement', + type: 'string' as const, + required: true, + description: 'The condition column and relational operator and condition value - For example: id,=,1', + variables: true, + }, + { + label: 'Run-time parameters', + key: 'params', + type: 'dynamic' as const, + required: false, + description: 'Change a run-time configuration parameter with command SET', + fields: [ + { + label: 'Parameter ', + key: 'configParam', + type: 'string' as const, + required: true, + variables: false, + }, + { + label: 'Value', + key: 'value', + type: 'string' as const, + required: true, + variables: true, + } + ], + } + ], + + async run($) { + const pgClient = await setConfig($) + + const params : any = $.step.parameters.params + if (params[0].configParam != '') + await setParams($, pgClient) + + const whereStatemennt = $.step.parameters.whereStatement as string + const whereParts = whereStatemennt.split(",") + + const conditionColumn = whereParts[0] + const RelationalOperator = whereParts[1] + const conditionValue = whereParts[2] + + const response = await pgClient(`${$.step.parameters.schema}.${$.step.parameters.table}`) + .returning('*') + .where(conditionColumn, RelationalOperator, conditionValue) + .del() as IJSONArray + + let deletedData : IJSONObject = {} + response.forEach( (ele: IJSONObject, i : number) => { deletedData[`record${i}`] = ele } ) + + $.setActionItem({ raw: deletedData as IJSONObject }); + }, +}); diff --git a/packages/backend/src/apps/postgres/actions/index.ts b/packages/backend/src/apps/postgres/actions/index.ts new file mode 100644 index 00000000..b882cf42 --- /dev/null +++ b/packages/backend/src/apps/postgres/actions/index.ts @@ -0,0 +1,6 @@ +import insertAction from './insert'; +import updateAction from './update'; +import deleteAction from './delete'; +import SQLQuery from './sql-query' + +export default [insertAction, updateAction, deleteAction, SQLQuery]; diff --git a/packages/backend/src/apps/postgres/actions/insert/index.ts b/packages/backend/src/apps/postgres/actions/insert/index.ts new file mode 100644 index 00000000..ed12b857 --- /dev/null +++ b/packages/backend/src/apps/postgres/actions/insert/index.ts @@ -0,0 +1,93 @@ +import { IJSONObject } from '@automatisch/types'; +import defineAction from '../../../../helpers/define-action'; +import setConfig from '../../common/postgres-configuration'; +import setParams from '../../common/set-run-time-parameters'; + +export default defineAction({ + name: 'Insert', + key: 'insert', + description: 'Cteate new item in a table in specific schema in postgreSQL.', + arguments: [ + { + label: 'Schema name', + key: 'schema', + type: 'string' as const, + value: 'public', + required: true, + description: 'The name of the schema.', + variables: false, + }, + { + label: 'Table name', + key: 'table', + type: 'string' as const, + required: true, + description: 'The name of the table.', + variables: false, + }, + { + label: 'Fields', + key: 'fields', + type: 'dynamic' as const, + required: true, + description: 'Table columns with values', + fields: [ + { + label: 'Column name', + key: 'columnName', + type: 'string' as const, + required: true, + variables: false, + }, + { + label: 'Value', + key: 'value', + type: 'string' as const, + required: true, + variables: true, + } + ], + }, + { + label: 'Run-time parameters', + key: 'params', + type: 'dynamic' as const, + required: false, + description: 'Change a run-time configuration parameter with command SET', + fields: [ + { + label: 'Parameter ', + key: 'configParam', + type: 'string' as const, + required: true, + variables: false, + }, + { + label: 'Value', + key: 'value', + type: 'string' as const, + required: true, + variables: true, + } + ], + } + ], + + async run($) { + const pgClient = await setConfig($) + + const params : any = $.step.parameters.params + if (params[0].configParam != '') + await setParams($, pgClient) + + const fields : any = $.step.parameters.fields + let data : IJSONObject = {} + fields.forEach( (ele: any) => { data[ele.columnName] = ele.value } ) + + const response = await pgClient(`${$.step.parameters.schema}.${$.step.parameters.table}`) + .returning('*') + .insert(data) as IJSONObject + + $.setActionItem({ raw: response[0] as IJSONObject }); + }, +}); diff --git a/packages/backend/src/apps/postgres/actions/sql-query/index.ts b/packages/backend/src/apps/postgres/actions/sql-query/index.ts new file mode 100644 index 00000000..6821ee0e --- /dev/null +++ b/packages/backend/src/apps/postgres/actions/sql-query/index.ts @@ -0,0 +1,60 @@ +import { IJSONObject } from '@automatisch/types'; +import defineAction from '../../../../helpers/define-action'; +import setConfig from '../../common/postgres-configuration'; +import setParams from '../../common/set-run-time-parameters'; + +export default defineAction({ + name: 'SQL query', + key: 'SQLQuery', + description: 'Cteate new item in a table in specific schema in postgreSQL.', + arguments: [ + { + label: 'SQL statement', + key: 'queryStatement', + type: 'string' as const, + value: 'public', + required: true, + description: 'Execute SQL query sttement directly.', + variables: true, + }, + { + label: 'Run-time parameters', + key: 'params', + type: 'dynamic' as const, + required: false, + description: 'Change a run-time configuration parameter with command SET', + fields: [ + { + label: 'Parameter ', + key: 'configParam', + type: 'string' as const, + required: true, + variables: false, + }, + { + label: 'Value', + key: 'value', + type: 'string' as const, + required: true, + variables: true, + } + ], + } + ], + + async run($) { + const pgClient = await setConfig($) + + const params : any = $.step.parameters.params + if (params[0].configParam != '') + await setParams($, pgClient) + + + const queryStatemnt = $.step.parameters.queryStatement + const response = await pgClient.raw(queryStatemnt); + + const res = { msg: `SQL query: " ${$.step.parameters.queryStatement} " has been executed successfully`} + + $.setActionItem({ raw: res as IJSONObject }); + }, +}); diff --git a/packages/backend/src/apps/postgres/actions/update/index.ts b/packages/backend/src/apps/postgres/actions/update/index.ts new file mode 100644 index 00000000..6aab1051 --- /dev/null +++ b/packages/backend/src/apps/postgres/actions/update/index.ts @@ -0,0 +1,112 @@ +import { IJSONObject, IJSONArray } from '@automatisch/types'; +import defineAction from '../../../../helpers/define-action'; +import setConfig from '../../common/postgres-configuration'; +import setParams from '../../common/set-run-time-parameters'; + +export default defineAction({ + name: 'Update', + key: 'update', + description: 'Cteate new item in a table in specific schema in postgreSQL.', + arguments: [ + { + label: 'Schema name', + key: 'schema', + type: 'string' as const, + value: 'public', + required: true, + description: 'The name of the schema.', + variables: false, + }, + { + label: 'Table name', + key: 'table', + type: 'string' as const, + required: true, + description: 'The name of the table.', + variables: false, + }, + { + label: 'Where statement', + key: 'whereStatement', + type: 'string' as const, + required: true, + description: 'The condition column and relational operator and condition value - For example: id,=,1', + variables: true, + }, + { + label: 'Fields', + key: 'fields', + type: 'dynamic' as const, + required: true, + description: 'Table columns with values', + fields: [ + { + label: 'Column name', + key: 'columnName', + type: 'string' as const, + required: true, + variables: false, + }, + { + label: 'Value', + key: 'value', + type: 'string' as const, + required: true, + variables: true, + } + ], + }, + { + label: 'Run-time parameters', + key: 'params', + type: 'dynamic' as const, + required: false, + description: 'Change a run-time configuration parameter with command SET', + fields: [ + { + label: 'Parameter ', + key: 'configParam', + type: 'string' as const, + required: true, + variables: false, + }, + { + label: 'Value', + key: 'value', + type: 'string' as const, + required: true, + variables: true, + } + ], + } + ], + + async run($) { + const pgClient = await setConfig($) + + const params : any = $.step.parameters.params + if (params[0].configParam != '') + await setParams($, pgClient) + + const whereStatemennt = $.step.parameters.whereStatement as string + const whereParts = whereStatemennt.split(",") + + const conditionColumn = whereParts[0] + const RelationalOperator = whereParts[1] + const conditionValue = whereParts[2] + + const fields : any = $.step.parameters.fields + let data : IJSONObject = {} + fields.forEach( (ele: any) => { data[ele.columnName] = ele.value } ) + + const response = await pgClient(`${$.step.parameters.schema}.${$.step.parameters.table}`) + .returning('*') + .where(conditionColumn, RelationalOperator, conditionValue) + .update(data) as IJSONArray + + let updatedData : IJSONObject = {} + response.forEach( (ele: IJSONObject, i : number) => { updatedData[`record${i}`] = ele } ) + + $.setActionItem({ raw: updatedData as IJSONObject }); + }, +}); diff --git a/packages/backend/src/apps/postgres/auth/index.ts b/packages/backend/src/apps/postgres/auth/index.ts new file mode 100644 index 00000000..f61f1a46 --- /dev/null +++ b/packages/backend/src/apps/postgres/auth/index.ts @@ -0,0 +1,85 @@ +import verifyCredentials from './verify-credentials'; +import isStillVerified from './is-still-verified'; + +export default { + fields: [ + { + key: 'version', + label: 'Postgres Version', + type: 'string' as const, + required: true, + readOnly: false, + value: null, + placeholder: null, + description: + 'The version of postgres database that user want to connect with.', + clickToCopy: false, + }, + { + key: 'host', + label: 'Host', + type: 'string' as const, + required: true, + readOnly: false, + value: null, + placeholder: null, + description: + 'The host of postgres database.', + clickToCopy: false, + }, + { + key: 'port', + label: 'Port', + type: 'string' as const, + required: true, + readOnly: false, + value: null, + placeholder: null, + description: + 'The port of postgres database.', + clickToCopy: false, + }, + { + key: 'database', + label: 'Database Name', + type: 'string' as const, + required: true, + readOnly: false, + value: null, + placeholder: null, + description: + 'The name of postgres database.', + clickToCopy: false, + }, + { + key: 'user', + label: 'Database User Name', + type: 'string' as const, + required: true, + readOnly: false, + value: null, + placeholder: null, + description: + 'The user who has access on postgres database.', + clickToCopy: false, + }, + { + key: 'password', + label: 'Password', + type: 'string' as const, + required: true, + readOnly: false, + value: null, + placeholder: null, + description: + 'The password of the user.', + clickToCopy: false, + }, + + ], + + verifyCredentials, + isStillVerified + }; + + diff --git a/packages/backend/src/apps/postgres/auth/is-still-verified.ts b/packages/backend/src/apps/postgres/auth/is-still-verified.ts new file mode 100644 index 00000000..40bb3c45 --- /dev/null +++ b/packages/backend/src/apps/postgres/auth/is-still-verified.ts @@ -0,0 +1,22 @@ +// import { IGlobalVariable } from '@automatisch/types'; +// import verifyCredentials from './verify-credentials'; +// import { Knex } from 'knex'; + +// const isStillVerified = async ($: IGlobalVariable) => { + +// await $.auth.data.pgClient.raw('SELECT 1') +// // await verifyCredentials($); +// return true; +// }; + +// export default isStillVerified; + +import { IGlobalVariable } from '@automatisch/types'; +import verifyCredentials from './verify-credentials'; + +const isStillVerified = async ($: IGlobalVariable) => { + await verifyCredentials($); + return true; +}; + +export default isStillVerified; diff --git a/packages/backend/src/apps/postgres/auth/verify-credentials.ts b/packages/backend/src/apps/postgres/auth/verify-credentials.ts new file mode 100644 index 00000000..d4233a3b --- /dev/null +++ b/packages/backend/src/apps/postgres/auth/verify-credentials.ts @@ -0,0 +1,57 @@ +import { IGlobalVariable } from '@automatisch/types'; +import logger from '../../../helpers/logger'; +import setConfig from '../common/postgres-configuration'; + + +const verifyCredentials = async ($: IGlobalVariable) => { + + const pgClient = await setConfig($) + const checkConnection = await pgClient.raw('SELECT 1') + logger.debug(checkConnection) + + await $.auth.set({ + screenName: `${$.auth.data.database} DB`, + client: 'pg', + version: $.auth.data.version, + host : $.auth.data.host, + port : $.auth.data.port, + user : $.auth.data.user, + password : $.auth.data.password, + database : $.auth.data.database + }); +}; + +export default verifyCredentials; + + +/* + +mutation Login($input: LoginInput) { login(input: $input) { token user { id email __typename } __typename }} + + +mutation CreateConnection($input: CreateConnectionInput) { createConnection(input: $input) { id key verified formattedData { screenName __typename } __typename }} + +{ + "input": + { + "key": "postgres", + "formattedData": { + "version":"15", + "host":"127.0.0.1", + "port":"6500", + "database":"bbs", + "user":"test", + "password":"@Test123" + } + } +} + +mutation VerifyConnection($input: VerifyConnectionInput) { verifyConnection(input: $input) { id key verified formattedData { screenName __typename } createdAt app { key __typename } __typename }} + + +{ + "input": +{"id": "18309778-ef78-41ae-be1b-ff51781134c0"} +} + +*/ \ No newline at end of file diff --git a/packages/backend/src/apps/postgres/common/postgres-configuration.ts b/packages/backend/src/apps/postgres/common/postgres-configuration.ts new file mode 100644 index 00000000..28c34eb8 --- /dev/null +++ b/packages/backend/src/apps/postgres/common/postgres-configuration.ts @@ -0,0 +1,22 @@ +import { IGlobalVariable } from '@automatisch/types'; +import knex, { Knex } from 'knex' + + +const setConfig = async ($: IGlobalVariable) : Promise> => { + const pgClient = knex({ + client: 'pg', + version: $.auth.data.version as string, + connection: { + host : $.auth.data.host as string, + port : $.auth.data.port as number, + user : $.auth.data.user as string, + password : $.auth.data.password as string, + database : $.auth.data.database as string + } + }) + + return pgClient; + +}; + +export default setConfig; diff --git a/packages/backend/src/apps/postgres/common/set-run-time-parameters.ts b/packages/backend/src/apps/postgres/common/set-run-time-parameters.ts new file mode 100644 index 00000000..dd5738c1 --- /dev/null +++ b/packages/backend/src/apps/postgres/common/set-run-time-parameters.ts @@ -0,0 +1,17 @@ +import { IGlobalVariable, IJSONObject } from '@automatisch/types'; +import { Knex } from 'knex' +import logger from '../../../helpers/logger'; + +const setParams = async ($: IGlobalVariable, client: Knex) : Promise> => { + + const params : any = $.step.parameters.params + let paramsObj : IJSONObject = {} + params.forEach( (ele: any) => { paramsObj[ele.configParam] = ele.value } ) + + for (const key in paramsObj) { + const res = await client.raw(`SET ${key} = '${paramsObj[key]}'`); + } + +}; + +export default setParams; diff --git a/packages/backend/src/apps/postgres/index.d.ts b/packages/backend/src/apps/postgres/index.d.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/backend/src/apps/postgres/index.ts b/packages/backend/src/apps/postgres/index.ts new file mode 100644 index 00000000..ec0c29fc --- /dev/null +++ b/packages/backend/src/apps/postgres/index.ts @@ -0,0 +1,17 @@ +import defineApp from '../../helpers/define-app'; +import auth from './auth'; +import actions from './actions'; + +export default defineApp({ + name: 'PostgreSQL DataBase', + key: 'postgres', + iconUrl: '{BASE_URL}/apps/thecatapi/assets/favicon.svg', + authDocUrl: 'https://automatisch.io/docs/apps/thecatapi/connection', + supportsConnections: true, + baseUrl: '', // https://thecatapi.com + apiBaseUrl: '', // https://api.thecatapi.com + primaryColor: '000000', + + auth, + actions +});