diff --git a/packages/backend/src/apps/datastore/actions/get-value/index.js b/packages/backend/src/apps/datastore/actions/get-value/index.js new file mode 100644 index 00000000..68f12d21 --- /dev/null +++ b/packages/backend/src/apps/datastore/actions/get-value/index.js @@ -0,0 +1,27 @@ +import defineAction from '../../../../helpers/define-action.js'; + +export default defineAction({ + name: 'Get value', + key: 'getValue', + description: 'Get value from the persistent datastore', + arguments: [ + { + label: 'Key', + key: 'key', + type: 'string', + required: true, + description: 'The key of your value to get.', + variables: true, + }, + ], + + async run($) { + const keyValuePair = await $.datastore.get({ + key: $.step.parameters.key, + }); + + $.setActionItem({ + raw: keyValuePair, + }); + }, +}); diff --git a/packages/backend/src/apps/datastore/actions/index.js b/packages/backend/src/apps/datastore/actions/index.js new file mode 100644 index 00000000..0d2b2212 --- /dev/null +++ b/packages/backend/src/apps/datastore/actions/index.js @@ -0,0 +1,4 @@ +import getValue from './get-value/index.js'; +import setValue from './set-value/index.js'; + +export default [getValue, setValue]; diff --git a/packages/backend/src/apps/datastore/actions/set-value/index.js b/packages/backend/src/apps/datastore/actions/set-value/index.js new file mode 100644 index 00000000..69d956fa --- /dev/null +++ b/packages/backend/src/apps/datastore/actions/set-value/index.js @@ -0,0 +1,36 @@ +import defineAction from '../../../../helpers/define-action.js'; + +export default defineAction({ + name: 'Set value', + key: 'setValue', + description: 'Set value to the persistent datastore', + arguments: [ + { + label: 'Key', + key: 'key', + type: 'string', + required: true, + description: 'The key of your value to set.', + variables: true, + }, + { + label: 'Value', + key: 'value', + type: 'string', + required: true, + description: 'The value to set.', + variables: true, + }, + ], + + async run($) { + const keyValuePair = await $.datastore.set({ + key: $.step.parameters.key, + value: $.step.parameters.value, + }); + + $.setActionItem({ + raw: keyValuePair, + }); + }, +}); diff --git a/packages/backend/src/apps/datastore/assets/favicon.svg b/packages/backend/src/apps/datastore/assets/favicon.svg new file mode 100644 index 00000000..c45032f5 --- /dev/null +++ b/packages/backend/src/apps/datastore/assets/favicon.svg @@ -0,0 +1,13 @@ + + + + + + datastore + + + + + + + diff --git a/packages/backend/src/apps/datastore/index.js b/packages/backend/src/apps/datastore/index.js new file mode 100644 index 00000000..eaa1d2ba --- /dev/null +++ b/packages/backend/src/apps/datastore/index.js @@ -0,0 +1,14 @@ +import defineApp from '../../helpers/define-app.js'; +import actions from './actions/index.js'; + +export default defineApp({ + name: 'Datastore', + key: 'datastore', + iconUrl: '{BASE_URL}/apps/datastore/assets/favicon.svg', + authDocUrl: 'https://automatisch.io/docs/apps/datastore/connection', + supportsConnections: false, + baseUrl: '', + apiBaseUrl: '', + primaryColor: '001F52', + actions, +}); diff --git a/packages/backend/src/db/migrations/20240227164849_create_datastore_model.js b/packages/backend/src/db/migrations/20240227164849_create_datastore_model.js new file mode 100644 index 00000000..c303989e --- /dev/null +++ b/packages/backend/src/db/migrations/20240227164849_create_datastore_model.js @@ -0,0 +1,16 @@ +export async function up(knex) { + return knex.schema.createTable('datastore', (table) => { + table.uuid('id').primary().defaultTo(knex.raw('gen_random_uuid()')); + table.string('key').notNullable(); + table.string('value'); + table.string('scope').notNullable(); + table.uuid('scope_id').notNullable(); + table.index(['key', 'scope', 'scope_id']); + + table.timestamps(true, true); + }); +} + +export async function down(knex) { + return knex.schema.dropTable('datastore'); +} diff --git a/packages/backend/src/helpers/global-variable.js b/packages/backend/src/helpers/global-variable.js index 168be47c..5f7706f9 100644 --- a/packages/backend/src/helpers/global-variable.js +++ b/packages/backend/src/helpers/global-variable.js @@ -1,6 +1,7 @@ import createHttpClient from './http-client/index.js'; import EarlyExitError from '../errors/early-exit.js'; import AlreadyProcessedError from '../errors/already-processed.js'; +import Datastore from '../models/datastore.js'; const globalVariable = async (options) => { const { @@ -88,6 +89,43 @@ const globalVariable = async (options) => { setActionItem: (actionItem) => { $.actionOutput.data = actionItem; }, + datastore: { + get: async ({ key }) => { + const datastore = await Datastore.query().findOne({ + key, + scope: 'flow', + scope_id: $.flow.id, + }); + + return { + key: datastore.key, + value: datastore.value, + [datastore.key]: datastore.value, + }; + }, + set: async ({ key, value }) => { + let datastore = await Datastore.query() + .where({ key, scope: 'flow', scope_id: $.flow.id }) + .first(); + + if (datastore) { + await datastore.$query().patchAndFetch({ value: value }); + } else { + datastore = await Datastore.query().insert({ + key, + value, + scope: 'flow', + scopeId: $.flow.id, + }); + } + + return { + key: datastore.key, + value: datastore.value, + [datastore.key]: datastore.value, + }; + }, + }, }; if (request) { diff --git a/packages/backend/src/models/datastore.js b/packages/backend/src/models/datastore.js new file mode 100644 index 00000000..91f80d29 --- /dev/null +++ b/packages/backend/src/models/datastore.js @@ -0,0 +1,24 @@ +import Base from './base.js'; + +class Datastore extends Base { + static tableName = 'datastore'; + + static jsonSchema = { + type: 'object', + required: ['key', 'value', 'scope', 'scopeId'], + + properties: { + id: { type: 'string', format: 'uuid' }, + key: { type: 'string', minLength: 1 }, + value: { type: 'string', minLength: 1 }, + scope: { + type: 'string', + enum: ['flow'], + default: 'flow', + }, + scopeId: { type: 'string', format: 'uuid' }, + }, + }; +} + +export default Datastore;