From 52ea1fe1da6838d74dcb369a4a5bf3ba5edc2c15 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Tue, 7 Dec 2021 12:26:00 +0000 Subject: [PATCH] Duplicate queries --- .../popovers/EditQueryPopover.svelte | 9 ++++ packages/builder/src/helpers/duplicate.js | 50 +++++++++++++++++++ .../src/helpers/tests/duplicate.spec.js | 42 ++++++++++++++++ .../builder/src/stores/backend/queries.js | 26 +++++++++- 4 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 packages/builder/src/helpers/duplicate.js create mode 100644 packages/builder/src/helpers/tests/duplicate.spec.js diff --git a/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte b/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte index 47f50c2739..98bc7e6c83 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte @@ -11,6 +11,14 @@ await queries.delete(query) notifications.success("Query deleted") } + + async function duplicateQuery() { + try { + await queries.duplicate(query, queries.save) + } catch (e) { + notifications.error(e.message) + } + } @@ -18,6 +26,7 @@ Delete + Duplicate { + const baseName = name.split(" (")[0] + const isDuplicate = new RegExp(`${baseName}\\s\\((\\d+)\\)$`) + + // get the sequence from matched names + const sequence = [] + allNames.filter(n => { + if (n === baseName) { + return true + } + const match = n.match(isDuplicate) + if (match) { + sequence.push(parseInt(match[1])) + return true + } + return false + }) + sequence.sort((a, b) => a - b) + + // get the next number in the sequence + let number + if (sequence.length === 0) { + number = 1 + } else { + // get the next number in the sequence + for (let i = 0; i < sequence.length; i++) { + if (sequence[i] !== i + 1) { + number = i + 1 + break + } + } + if (!number) { + number = sequence.length + 1 + } + } + + return `${baseName} (${number})` +} diff --git a/packages/builder/src/helpers/tests/duplicate.spec.js b/packages/builder/src/helpers/tests/duplicate.spec.js new file mode 100644 index 0000000000..cecf35b545 --- /dev/null +++ b/packages/builder/src/helpers/tests/duplicate.spec.js @@ -0,0 +1,42 @@ +const { duplicateName } = require("../duplicate") + +describe("duplicate", () => { + + describe("duplicates a name ", () => { + it("with a single existing", async () => { + const names = ["foo"] + const name = "foo" + + const duplicate = duplicateName(name, names) + + expect(duplicate).toBe("foo (1)") + }) + + it("with multiple existing", async () => { + const names = ["foo", "foo (1)", "foo (2)"] + const name = "foo" + + const duplicate = duplicateName(name, names) + + expect(duplicate).toBe("foo (3)") + }) + + it("with mixed multiple existing", async () => { + const names = ["foo", "foo (1)", "foo (2)", "bar", "bar (1)", "bar (2)"] + const name = "foo" + + const duplicate = duplicateName(name, names) + + expect(duplicate).toBe("foo (3)") + }) + + it("with incomplete sequence", async () => { + const names = ["foo", "foo (2)", "foo (3)"] + const name = "foo" + + const duplicate = duplicateName(name, names) + + expect(duplicate).toBe("foo (1)") + }) + }) +}) diff --git a/packages/builder/src/stores/backend/queries.js b/packages/builder/src/stores/backend/queries.js index 020a0c9420..d07f6d2f6c 100644 --- a/packages/builder/src/stores/backend/queries.js +++ b/packages/builder/src/stores/backend/queries.js @@ -1,9 +1,17 @@ import { writable, get } from "svelte/store" import { datasources, integrations, tables, views } from "./" import api from "builderStore/api" +import { duplicateName } from "../../helpers/duplicate" + +const sortQueries = queryList => { + queryList.sort((q1, q2) => { + return q1.name.localeCompare(q2.name) + }) +} export function createQueriesStore() { - const { subscribe, set, update } = writable({ list: [], selected: null }) + const store = writable({ list: [], selected: null }) + const { subscribe, set, update } = store return { subscribe, @@ -17,6 +25,7 @@ export function createQueriesStore() { fetch: async () => { const response = await api.get(`/api/queries`) const json = await response.json() + sortQueries(json) update(state => ({ ...state, list: json })) return json }, @@ -49,6 +58,7 @@ export function createQueriesStore() { } else { queries.push(json) } + sortQueries(queries) return { list: queries, selected: json._id } }) return json @@ -76,6 +86,20 @@ export function createQueriesStore() { }) return response }, + duplicate: async (query, saveFn) => { + let list = get(store).list + const newQuery = { ...query } + const datasourceId = query.datasourceId + + delete newQuery._id + delete newQuery._rev + newQuery.name = duplicateName( + query.name, + list.map(q => q.name) + ) + + saveFn(datasourceId, newQuery) + }, } }