Skip to content

Commit

Permalink
feat: add find and replace for passport variable via cli prompts (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mike-Heneghan authored Feb 19, 2024
1 parent 0c293d0 commit 85b2d25
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 0 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"test": "echo \"Error: no test specified\" && exit 1",
"start:fileNames": "node fileNames/index.js",
"start:titleBoundary": "node titleBoundary/index.js",
"start:passportValue": "node passportValue/index.js",
"precommit": "prettier --write **/*.js && git add ."
},
"keywords": [],
Expand Down
17 changes: 17 additions & 0 deletions passportValue/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* Find a current passport variable (fn) or (val) and replace it in each node in a flow (live or published
*/

const updateNodeFn = (flowData, currentPassportVariable, newPassportVariable) => {
let newFlowData = flowData;
Object.entries(flowData)
.filter(([_nodeId, nodeData]) => nodeData?.["data"]?.["fn"] || nodeData?.["data"]?.["val"])
.forEach(([nodeId, nodeData]) => {
const passportKey = nodeData["data"]["fn"] ? "fn" : "val"
const currentFn = nodeData["data"][`${passportKey}`]
newFlowData[nodeId]["data"][`${passportKey}`] = currentFn.replaceAll(currentPassportVariable, newPassportVariable)
})
return newFlowData;
}

module.exports = { updateNodeFn };
95 changes: 95 additions & 0 deletions passportValue/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
const ask = require("prompt");
const chalk = require("chalk");
const Client = require("../client");

const { findAndReplacePrompts } = require("./prompts");
const { updateNodeFn } = require("./helpers");

ask.start();

(async function go() {
// greeting
console.log(
chalk.cyan(
`Hello! These prompts will step you through updating a PlanX passport variables.\nType values when prompted or click 'enter' to accept ${chalk.white(
"(default)"
)} values.\n~~~~~~~~~~~~~~ ${chalk.bold("LET'S START")} ~~~~~~~~~~~~~~`
)
);

// authentication & setup
const { hasuraEnvironment, hasuraSecret, flowSlug, currentPassportVariable, newPassportVariable } = await ask.get(
findAndReplacePrompts
);
const url = {
production: "https://hasura.editor.planx.uk/v1/graphql",
staging: "https://hasura.editor.planx.dev/v1/graphql",
local: "http://localhost:7100/v1/graphql",
};

// create graphQL client
const client = new Client({
hasuraSecret,
targetURL: url[hasuraEnvironment],
});

const formattedSlug = flowSlug.toLowerCase().trim().replaceAll(" ", "-");

// Fetch flows matching slugs
const flows = await client.getFlowData(formattedSlug);
if (flows?.length > 0) {
console.log(chalk.white(`Fetched ${flows.length} flows`));

flows.forEach(async (flow, i) => {
let liveFlowData;
let publishedFlowData;
let response;

try {
if (flow.publishedFlows.length > 0) {
// Proceed with migration for flows that are published
console.log(chalk.white(`Updating published flow ${i+1}/${flows.length}: ${flow.team.slug}/${flow.slug}`));

// Find nodes in live flow data, update them
// This does NOT require a corresponding operation because we are not creating the flow for the first time
liveFlowData = updateNodeFn(flow.data, currentPassportVariable, newPassportVariable);

// Find nodes in published flow data, update them directly too
publishedFlowData = updateNodeFn(flow.publishedFlows?.[0]?.data, currentPassportVariable, newPassportVariable);

// Write update in a single mutation block for postgres transaction-like rollback behavior on error
response = await client.updateFlowAndPublishedFlow(flow.id, liveFlowData, flow.publishedFlows?.[0]?.id, publishedFlowData);
if (response?.update_flows_by_pk?.id) {
console.log(
chalk.green(`Successfully updated flow: ${flow.team.slug}/${flow.slug}`)
);
}
if (response?.update_published_flows_by_pk?.id) {
console.log(
chalk.green(`Successfully updated published version of flow: ${flow.team.slug}/${flow.slug}`)
);
}
} else {
// Proceed with migration for flows that are not published
console.log(chalk.white(`Updating unpublished flow ${i+1}/${flows.length}: ${flow.team.slug}/${flow.slug}`));

// Find nodes in live flow data, update them
// This does NOT require a corresponding operation because we are not creating the flow for the first time
liveFlowData = updateNodeFn(flow.data, currentPassportVariable, newPassportVariable);

// Write update
response = await client.updateFlow(flow.id, liveFlowData);
if (response?.update_flows_by_pk?.id) {
console.log(
chalk.green(`Successfully updated flow: ${flow.team.slug}/${flow.slug}`)
);
}
}
} catch (error) {
console.log(chalk.red(error));
}
});
} else {
console.log(chalk.red(`Cannot find any flows matching slug: ${formattedSlug}. Exiting migration script`));
}
})();
22 changes: 22 additions & 0 deletions passportValue/prompts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const { setupPrompts } = require("../prompts");

const findAndReplacePrompts= [
...setupPrompts,
{
name: "currentPassportVariable",
description: "What is the current passport variable to be replaced?",
default: "outbuildings",
type: "string",
required: true,
},
{
name: "newPassportVariable",
description: "What should this passport variable be replaced with?",
default: "outbuilding",
type: "string",
required: true,
},

];

module.exports = { findAndReplacePrompts };

0 comments on commit 85b2d25

Please sign in to comment.