From 52ea1fe1da6838d74dcb369a4a5bf3ba5edc2c15 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Tue, 7 Dec 2021 12:26:00 +0000 Subject: [PATCH 1/2] 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) + }, } } From 4f642a03a46803f8cb91ede9a01f87f48dba8ff7 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Wed, 8 Dec 2021 11:01:12 +0000 Subject: [PATCH 2/2] Refactor store actions to allow self reference --- .../popovers/EditQueryPopover.svelte | 2 +- packages/builder/src/stores/backend/queries.js | 16 ++++++++++------ .../src/stores/backend/tests/queries.spec.js | 1 - 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte b/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte index 98bc7e6c83..78e8da400b 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/popovers/EditQueryPopover.svelte @@ -14,7 +14,7 @@ async function duplicateQuery() { try { - await queries.duplicate(query, queries.save) + await queries.duplicate(query) } catch (e) { notifications.error(e.message) } diff --git a/packages/builder/src/stores/backend/queries.js b/packages/builder/src/stores/backend/queries.js index d07f6d2f6c..d45c9d4c8e 100644 --- a/packages/builder/src/stores/backend/queries.js +++ b/packages/builder/src/stores/backend/queries.js @@ -13,10 +13,7 @@ export function createQueriesStore() { const store = writable({ list: [], selected: null }) const { subscribe, set, update } = store - return { - subscribe, - set, - update, + const actions = { init: async () => { const response = await api.get(`/api/queries`) const json = await response.json() @@ -86,7 +83,7 @@ export function createQueriesStore() { }) return response }, - duplicate: async (query, saveFn) => { + duplicate: async query => { let list = get(store).list const newQuery = { ...query } const datasourceId = query.datasourceId @@ -98,9 +95,16 @@ export function createQueriesStore() { list.map(q => q.name) ) - saveFn(datasourceId, newQuery) + actions.save(datasourceId, newQuery) }, } + + return { + subscribe, + set, + update, + ...actions, + } } export const queries = createQueriesStore() diff --git a/packages/builder/src/stores/backend/tests/queries.spec.js b/packages/builder/src/stores/backend/tests/queries.spec.js index 1d1a1d0154..b4c1805c66 100644 --- a/packages/builder/src/stores/backend/tests/queries.spec.js +++ b/packages/builder/src/stores/backend/tests/queries.spec.js @@ -6,7 +6,6 @@ jest.mock('builderStore/api'); import { SOME_QUERY, SAVE_QUERY_RESPONSE } from './fixtures/queries' import { createQueriesStore } from "../queries" -import { datasources } from '../datasources' describe("Queries Store", () => { let store = createQueriesStore()