diff --git a/components/data_stores/actions/add-update-multiple-records/add-update-multiple-records.mjs b/components/data_stores/actions/add-update-multiple-records/add-update-multiple-records.mjs index 51596f69fffca..1927ff7a64564 100644 --- a/components/data_stores/actions/add-update-multiple-records/add-update-multiple-records.mjs +++ b/components/data_stores/actions/add-update-multiple-records/add-update-multiple-records.mjs @@ -4,7 +4,7 @@ export default { key: "data_stores-add-update-multiple-records", name: "Add or update multiple records", description: "Add or update multiple records to your [Pipedream Data Store](https://pipedream.com/data-stores/).", - version: "0.0.6", + version: "0.0.7", type: "action", props: { app, @@ -19,6 +19,12 @@ export default { type: "object", description: "Enter data you'd like to add as key-value pairs, or reference an object from a previous step using a custom expression (e.g., `{{steps.data.$return_value}}`). Note that any keys that are duplicated will get overwritten with the last value entered (so `[{jerry: \"constanza\", jerry: \"seinfeld\"}]` will get stored as `[{jerry: \"seinfeld\"}]`).", }, + ttl: { + propDefinition: [ + app, + "ttl", + ], + }, }, methods: { /** @@ -83,14 +89,30 @@ export default { } const map = this.getHashMapOfData(this.data); const keys = Object.keys(map); - const promises = Object.keys(map).map((key) => this.dataStore.set(key, map[key])); + + const promises = Object.keys(map).map((key) => { + if (this.ttl) { + return this.dataStore.set(key, map[key], { + ttl: this.ttl, + }); + } else { + return this.dataStore.set(key, map[key]); + } + }); + await Promise.all(promises); + if (keys.length === 0) { $.export("$summary", "No data was added to the data store."); } else { // eslint-disable-next-line multiline-ternary - $.export("$summary", `Successfully added or updated ${keys.length} record${keys.length === 1 ? "" : "s"}`); + $.export("$summary", `Successfully added or updated ${keys.length} record${keys.length === 1 ? "" : "s"}${this.ttl ? ` (expires in ${this.app.formatTtl(this.ttl)})` : ""}`); } - return map; + + // Include TTL in the returned map + return { + ...map, + _ttl: this.ttl || null, + }; }, }; diff --git a/components/data_stores/actions/add-update-record/add-update-record.mjs b/components/data_stores/actions/add-update-record/add-update-record.mjs index 5bf243388e0f0..490d6403ff2b7 100644 --- a/components/data_stores/actions/add-update-record/add-update-record.mjs +++ b/components/data_stores/actions/add-update-record/add-update-record.mjs @@ -4,7 +4,7 @@ export default { key: "data_stores-add-update-record", name: "Add or update a single record", description: "Add or update a single record in your [Pipedream Data Store](https://pipedream.com/data-stores/).", - version: "0.0.9", + version: "0.0.10", type: "action", props: { app, @@ -30,20 +30,36 @@ export default { "value", ], }, + ttl: { + propDefinition: [ + app, + "ttl", + ], + }, }, async run({ $ }) { const { key, value, + ttl, } = this; const exists = await this.dataStore.has(key); const parsedValue = this.app.parseValue(value); - await this.dataStore.set(key, parsedValue); + + if (ttl) { + await this.dataStore.set(key, parsedValue, { + ttl, + }); + } else { + await this.dataStore.set(key, parsedValue); + } + // eslint-disable-next-line multiline-ternary - $.export("$summary", `Successfully ${exists ? "updated the record for" : "added a new record with the"} key, \`${key}\`.`); + $.export("$summary", `Successfully ${exists ? "updated the record for" : "added a new record with the"} key, \`${key}\`${ttl ? ` (expires in ${this.app.formatTtl(ttl)})` : ""}.`); return { key, value: parsedValue, + ttl: ttl || null, }; }, }; diff --git a/components/data_stores/actions/append-to-record/append-to-record.mjs b/components/data_stores/actions/append-to-record/append-to-record.mjs index 95ddaf5edbd65..42e8a8a403c2d 100644 --- a/components/data_stores/actions/append-to-record/append-to-record.mjs +++ b/components/data_stores/actions/append-to-record/append-to-record.mjs @@ -5,7 +5,7 @@ export default { key: "data_stores-append-to-record", name: "Append to record", description: "Append to a record in your data store [Pipedream Data Store](https://pipedream.com/data-stores/). If the record does not exist, a new record will be created in an array format.", - version: "0.0.2", + version: "0.0.3", type: "action", props: { app, @@ -31,11 +31,18 @@ export default { "value", ], }, + ttl: { + propDefinition: [ + app, + "ttl", + ], + }, }, async run({ $ }) { const { key, value, + ttl, } = this; const currentValue = await this.dataStore.get(key); if (currentValue && !Array.isArray(currentValue)) { @@ -44,12 +51,23 @@ export default { const recordSet = currentValue ?? []; const parsedValue = this.app.parseValue(value); recordSet.push(parsedValue); - await this.dataStore.set(key, recordSet); - // eslint-disable-next-line multiline-ternary - $.export("$summary", `Successfully ${currentValue ? "appended to the record for" : "created new record with the"} key: \`${key}\`.`); + + if (ttl) { + await this.dataStore.set(key, recordSet, { + ttl, + }); + // eslint-disable-next-line multiline-ternary + $.export("$summary", `Successfully ${currentValue ? "appended to the record for" : "created new record with the"} key: \`${key}\` (expires in ${this.app.formatTtl(ttl)}).`); + } else { + await this.dataStore.set(key, recordSet); + // eslint-disable-next-line multiline-ternary + $.export("$summary", `Successfully ${currentValue ? "appended to the record for" : "created new record with the"} key: \`${key}\`.`); + } + return { key, value: parsedValue, + ttl: ttl || null, }; }, }; diff --git a/components/data_stores/actions/delete-all-records/delete-all-records.mjs b/components/data_stores/actions/delete-all-records/delete-all-records.mjs index 5b4554c648094..3ff3152d6d846 100644 --- a/components/data_stores/actions/delete-all-records/delete-all-records.mjs +++ b/components/data_stores/actions/delete-all-records/delete-all-records.mjs @@ -4,7 +4,7 @@ export default { key: "data_stores-delete-all-records", name: "Delete All Records", description: "Delete all records in your [Pipedream Data Store](https://pipedream.com/data-stores/).", - version: "0.0.2", + version: "0.0.3", type: "action", props: { app, diff --git a/components/data_stores/actions/delete-single-record/delete-single-record.mjs b/components/data_stores/actions/delete-single-record/delete-single-record.mjs index 4f408afdfa745..f9c7c5b6a7869 100644 --- a/components/data_stores/actions/delete-single-record/delete-single-record.mjs +++ b/components/data_stores/actions/delete-single-record/delete-single-record.mjs @@ -4,7 +4,7 @@ export default { key: "data_stores-delete-single-record", name: "Delete a single record", description: "Delete a single record in your [Pipedream Data Store](https://pipedream.com/data-stores/).", - version: "0.0.8", + version: "0.0.9", type: "action", props: { app, diff --git a/components/data_stores/actions/get-all-records/get-all-records.mjs b/components/data_stores/actions/get-all-records/get-all-records.mjs index fd6c4932633d8..d3f36b086efb8 100644 --- a/components/data_stores/actions/get-all-records/get-all-records.mjs +++ b/components/data_stores/actions/get-all-records/get-all-records.mjs @@ -4,7 +4,7 @@ export default { key: "data_stores-get-all-records", name: "Get all records", description: "Get all records in your [Pipedream Data Store](https://pipedream.com/data-stores/). The memory consumption of the workflow can be affected, since this action will be exposing, to the workflow, the entire data from the selected datastore.", - version: "0.0.3", + version: "0.0.4", type: "action", props: { app, diff --git a/components/data_stores/actions/get-difference/get-difference.mjs b/components/data_stores/actions/get-difference/get-difference.mjs index 50fb394d08dec..5ee0eb14315dc 100644 --- a/components/data_stores/actions/get-difference/get-difference.mjs +++ b/components/data_stores/actions/get-difference/get-difference.mjs @@ -5,7 +5,7 @@ export default { key: "data_stores-get-difference", name: "Get Difference", description: "Get the difference between two data stores. Result contains key/value pairs where the key exists in one data store, but not the other. [Pipedream Data Stores](https://pipedream.com/data-stores/).", - version: "0.0.2", + version: "0.0.3", type: "action", props: { app, diff --git a/components/data_stores/actions/get-record-keys/get-record-keys.mjs b/components/data_stores/actions/get-record-keys/get-record-keys.mjs index e44d66f6f5237..511d990c556db 100644 --- a/components/data_stores/actions/get-record-keys/get-record-keys.mjs +++ b/components/data_stores/actions/get-record-keys/get-record-keys.mjs @@ -4,7 +4,7 @@ export default { key: "data_stores-get-record-keys", name: "Get Record Keys", description: "Get all record keys in your [Pipedream Data Store](https://pipedream.com/data-stores/) that matches with your query. The memory consumption of the workflow can be affected, since this action will be exposing, to the workflow, the entire data from the selected datastore", - version: "0.0.3", + version: "0.0.4", type: "action", props: { app, diff --git a/components/data_stores/actions/get-record-or-create/get-record-or-create.mjs b/components/data_stores/actions/get-record-or-create/get-record-or-create.mjs index c1f186f326c27..898a88fe5a1e7 100644 --- a/components/data_stores/actions/get-record-or-create/get-record-or-create.mjs +++ b/components/data_stores/actions/get-record-or-create/get-record-or-create.mjs @@ -4,7 +4,7 @@ export default { key: "data_stores-get-record-or-create", name: "Get record (or create one if not found)", description: "Get a single record in your [Pipedream Data Store](https://pipedream.com/data-stores/) or create one if it doesn't exist.", - version: "0.0.10", + version: "0.0.11", type: "action", props: { app, @@ -30,6 +30,12 @@ export default { "addRecordIfNotFound", ], }, + ttl: { + propDefinition: [ + app, + "ttl", + ], + }, }, async additionalProps() { const props = {}; @@ -52,8 +58,25 @@ export default { } const parsedValue = this.app.parseValue(this.value); - await this.dataStore.set(this.key, parsedValue); - $.export("$summary", `Successfully added a new record with the key, \`${this.key}\`.`); + + if (this.ttl) { + await this.dataStore.set(this.key, parsedValue, { + ttl: this.ttl, + }); + $.export("$summary", `Successfully added a new record with the key, \`${this.key}\` (expires in ${this.app.formatTtl(this.ttl)}).`); + } else { + await this.dataStore.set(this.key, parsedValue); + $.export("$summary", `Successfully added a new record with the key, \`${this.key}\`.`); + } + + // Include TTL information in the return value if it was set + if (this.ttl) { + return { + value: parsedValue, + ttl: this.ttl, + }; + } + return parsedValue; }, }; diff --git a/components/data_stores/actions/has-key-or-create/has-key-or-create.mjs b/components/data_stores/actions/has-key-or-create/has-key-or-create.mjs index 7ff146fcdcd0e..73196b670db5e 100644 --- a/components/data_stores/actions/has-key-or-create/has-key-or-create.mjs +++ b/components/data_stores/actions/has-key-or-create/has-key-or-create.mjs @@ -4,7 +4,7 @@ export default { key: "data_stores-has-key-or-create", name: "Check for existence of key", description: "Check if a key exists in your [Pipedream Data Store](https://pipedream.com/data-stores/) or create one if it doesn't exist.", - version: "0.1.2", + version: "0.1.3", type: "action", props: { app, @@ -30,6 +30,12 @@ export default { "addRecordIfNotFound", ], }, + ttl: { + propDefinition: [ + app, + "ttl", + ], + }, }, async additionalProps() { const props = {}; @@ -58,13 +64,22 @@ export default { } const parsedValue = this.app.parseValue(this.value); - await this.dataStore.set(this.key, parsedValue); - $.export("$summary", `Key \`${this.key}\` was not found. Successfully added a new record.`); + + if (this.ttl) { + await this.dataStore.set(this.key, parsedValue, { + ttl: this.ttl, + }); + $.export("$summary", `Key \`${this.key}\` was not found. Successfully added a new record (expires in ${this.app.formatTtl(this.ttl)}).`); + } else { + await this.dataStore.set(this.key, parsedValue); + $.export("$summary", `Key \`${this.key}\` was not found. Successfully added a new record.`); + } return { existingKeyFound: false, newKeyCreated: true, value: parsedValue, + ttl: this.ttl || null, }; }, }; diff --git a/components/data_stores/actions/list-keys/list-keys.mjs b/components/data_stores/actions/list-keys/list-keys.mjs index 4754160af28a2..d91a33689cc8c 100644 --- a/components/data_stores/actions/list-keys/list-keys.mjs +++ b/components/data_stores/actions/list-keys/list-keys.mjs @@ -4,7 +4,7 @@ export default { key: "data_stores-list-keys", name: "List keys", description: "List all keys in your [Pipedream Data Store](https://pipedream.com/data-stores/).", - version: "0.0.2", + version: "0.0.3", type: "action", props: { app, diff --git a/components/data_stores/actions/list-records/list-records.mjs b/components/data_stores/actions/list-records/list-records.mjs index 4cea26a9ea017..4d267c406402b 100644 --- a/components/data_stores/actions/list-records/list-records.mjs +++ b/components/data_stores/actions/list-records/list-records.mjs @@ -6,7 +6,7 @@ export default { key: "data_stores-list-records", name: "List Records", description: "List all records in your [Pipedream Data Store](https://pipedream.com/data-stores/).", - version: "0.0.3", + version: "0.0.4", type: "action", props: { app, diff --git a/components/data_stores/actions/update-ttl/update-ttl.mjs b/components/data_stores/actions/update-ttl/update-ttl.mjs new file mode 100644 index 0000000000000..acfbf47cdcf5f --- /dev/null +++ b/components/data_stores/actions/update-ttl/update-ttl.mjs @@ -0,0 +1,121 @@ +import app from "../../data_stores.app.mjs"; + +export default { + key: "data_stores-update-ttl", + name: "Update Record Expiration", + description: "Update the expiration time for a record in your [Pipedream Data Store](https://pipedream.com/data-stores/).", + version: "0.0.1", + type: "action", + props: { + app, + dataStore: { + propDefinition: [ + app, + "dataStore", + ], + }, + key: { + propDefinition: [ + app, + "key", + ({ dataStore }) => ({ + dataStore, + }), + ], + description: "Select the key for the record you'd like to update the expiration time.", + }, + ttlOption: { + type: "string", + label: "Expiration Type", + description: "Choose a common expiration time or specify a custom value", + options: [ + { + label: "Custom value", + value: "custom", + }, + { + label: "No expiration (remove expiry)", + value: "0", + }, + { + label: "1 hour", + value: "3600", + }, + { + label: "1 day", + value: "86400", + }, + { + label: "1 week", + value: "604800", + }, + { + label: "30 days", + value: "2592000", + }, + { + label: "90 days", + value: "7776000", + }, + { + label: "1 year", + value: "31536000", + }, + ], + reloadProps: true, + }, + }, + async additionalProps() { + const props = {}; + if (this.ttlOption === "custom") { + props.ttl = { + type: "integer", + label: "Custom TTL (seconds)", + description: "The number of seconds until this record expires and is automatically deleted. Use 0 to remove expiration.", + min: 0, + max: 31536000, // 1 year (safe upper limit) + }; + } + return props; + }, + async run({ $ }) { + const { + key, ttlOption, ttl, + } = this; + + // Determine TTL value to use + const ttlValue = ttlOption === "custom" + ? ttl + : parseInt(ttlOption, 10); + + if (!await this.dataStore.has(key)) { + $.export("$summary", `No record found with key \`${key}\`.`); + return { + success: false, + message: `No record found with key ${key}`, + }; + } + + if (ttlValue === 0) { + // Remove expiration + await this.dataStore.setTtl(key, null); + $.export("$summary", `Successfully removed expiration for key \`${key}\`.`); + return { + success: true, + key, + ttl: null, + message: "Expiration removed", + }; + } else { + // Update TTL + await this.dataStore.setTtl(key, ttlValue); + $.export("$summary", `Successfully updated expiration for key \`${key}\` (expires in ${this.app.formatTtl(ttlValue)}).`); + return { + success: true, + key, + ttl: ttlValue, + ttlFormatted: this.app.formatTtl(ttlValue), + }; + } + }, +}; diff --git a/components/data_stores/data_stores.app.mjs b/components/data_stores/data_stores.app.mjs index 2bf4ed49291d4..65f6e2e3a1b2d 100644 --- a/components/data_stores/data_stores.app.mjs +++ b/components/data_stores/data_stores.app.mjs @@ -27,6 +27,14 @@ export default { type: "any", description: "Enter a string, object, or array.", }, + ttl: { + label: "Time to Live (TTL)", + type: "integer", + description: "The number of seconds until this record expires and is automatically deleted. Examples: 3600 (1 hour), 86400 (1 day), 604800 (1 week). Leave blank for records that should not expire.", + optional: true, + min: 0, + max: 31536000, // 1 year (safe upper limit) + }, addRecordIfNotFound: { label: "Create a new record if the key is not found?", description: "Create a new record if no records are found for the specified key.", @@ -66,5 +74,46 @@ export default { return value; } }, + formatTtl(seconds) { + if (!seconds) return ""; + + // Format TTL in a human-readable way + if (seconds < 60) { + return `${seconds} second${seconds === 1 + ? "" + : "s"}`; + } + if (seconds < 3600) { + const minutes = Math.round(seconds / 60); + return `${minutes} minute${minutes === 1 + ? "" + : "s"}`; + } + if (seconds < 86400) { + const hours = Math.round(seconds / 3600); + return `${hours} hour${hours === 1 + ? "" + : "s"}`; + } + if (seconds < 604800) { + const days = Math.round(seconds / 86400); + return `${days} day${days === 1 + ? "" + : "s"}`; + } + const weeks = Math.round(seconds / 604800); + return `${weeks} week${weeks === 1 + ? "" + : "s"}`; + }, + async updateTtlIfNeeded(dataStore, key, ttl) { + if (!ttl) return false; + + if (await dataStore.has(key)) { + await dataStore.setTtl(key, ttl); + return true; + } + return false; + }, }, }; diff --git a/components/data_stores/package.json b/components/data_stores/package.json index b77dd6d34fa05..bef5b8ac1c6c7 100644 --- a/components/data_stores/package.json +++ b/components/data_stores/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/data_stores", - "version": "0.1.5", + "version": "0.1.6", "description": "Pipedream Data Stores Components", "main": "data_stores.app.js", "keywords": [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b5218db58b95f..7c1f30a8f3514 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5988,8 +5988,7 @@ importers: specifier: ^1.6.0 version: 1.6.6 - components/hr_cloud: - specifiers: {} + components/hr_cloud: {} components/hr_partner: {} @@ -6500,8 +6499,7 @@ importers: components/jellyreach: {} - components/jenkins: - specifiers: {} + components/jenkins: {} components/jibble: dependencies: @@ -11961,8 +11959,7 @@ importers: specifier: ^1.2.0 version: 1.6.6 - components/splunk: - specifiers: {} + components/splunk: {} components/splunk_http_event_collector: {}