Skip to content

Commit 13bda66

Browse files
authored
properly delete connected edges when deleting pods (#228)
1 parent cb0628c commit 13bda66

File tree

5 files changed

+56
-41
lines changed

5 files changed

+56
-41
lines changed

api/src/resolver_repo.ts

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -433,46 +433,58 @@ async function addPods(_, { repoId, pods }, { userId }) {
433433
return true;
434434
}
435435

436-
async function deletePod(_, { id, toDelete }, { userId }) {
436+
async function deletePods(_, { ids }: { ids: string[] }, { userId }) {
437437
if (!userId) throw new Error("Not authenticated.");
438-
await ensurePodEditAccess({ id, userId });
439-
// find all children of this ID
440-
// FIXME how to ensure atomic
441-
// 1. find the parent of this node
438+
if (ids.length === 0) return false;
439+
// find the repo
442440
const pod = await prisma.pod.findFirst({
443-
where: {
444-
id: id,
445-
},
446-
include: {
447-
parent: true,
448-
},
441+
where: { id: ids[0] },
442+
include: { repo: true },
449443
});
450444
if (!pod) throw new Error("Pod not found");
445+
await ensureRepoEditAccess({ repoId: pod.repo.id, userId });
446+
// If the pod is connected to a scope, the frontend will fire deleteEdge calls
447+
// as well simultaneously. Thus, if this call is fired before the edges are
448+
// deleted, an error will be thrown.
449+
//
450+
// Additional Notes:
451+
// 1. The deleteEdge graphQL call will still be fired. This would be redundant
452+
// but should be fine.
453+
// 2. We still need the deleteEdge graphQL calls when the edge is selected and
454+
// deleted.
451455

452-
// 4. update all siblings index
453-
await prisma.pod.updateMany({
456+
const deletedEdges = await prisma.edge.deleteMany({
454457
where: {
455-
// CAUTION where to put null is tricky
456-
parent: pod.parent
457-
? {
458-
id: pod.parent.id,
459-
}
460-
: null,
461-
index: {
462-
gt: pod.index,
463-
},
464-
},
465-
data: {
466-
index: {
467-
decrement: 1,
458+
OR: [
459+
{
460+
source: {
461+
id: {
462+
in: ids,
463+
},
464+
},
465+
},
466+
{
467+
target: {
468+
id: {
469+
in: ids,
470+
},
471+
},
472+
},
473+
],
474+
repo: {
475+
id: pod.repo.id,
468476
},
469477
},
470478
});
471-
// 5. delete it and all its children
472-
await prisma.pod.deleteMany({
479+
480+
// delete all the nodes, but make sure they are in this exact repo.
481+
const deletedPods = await prisma.pod.deleteMany({
473482
where: {
474483
id: {
475-
in: toDelete,
484+
in: ids,
485+
},
486+
repo: {
487+
id: pod.repo.id,
476488
},
477489
},
478490
});
@@ -492,7 +504,7 @@ export default {
492504
updateRepo,
493505
deleteRepo,
494506
updatePod,
495-
deletePod,
507+
deletePods,
496508
addEdge,
497509
deleteEdge,
498510
addCollaborator,

api/src/typedefs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export const typeDefs = gql`
124124
createRepo: Repo
125125
updateRepo(id: ID!, name: String!): Boolean
126126
deleteRepo(id: ID!): Boolean
127-
deletePod(id: String!, toDelete: [String]): Boolean
127+
deletePods(ids: [String]): Boolean
128128
addPods(repoId: String!, pods: [PodInput]): Boolean
129129
updatePod(id: String!, repoId: String!, input: PodInput): Boolean
130130
addEdge(source: ID!, target: ID!): Boolean

ui/src/components/nodes/Code.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ function FloatingToolbar({ id }) {
305305
<IconButton
306306
size="small"
307307
onClick={() => {
308+
// Delete all edges connected to the node.
308309
reactFlowInstance.deleteElements({ nodes: [{ id }] });
309310
}}
310311
>

ui/src/lib/fetch.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,17 +215,19 @@ function serializePodInput(pod) {
215215
}))(pod);
216216
}
217217

218-
export async function doRemoteDeletePod(client, { id, toDelete }) {
218+
export async function doRemoteDeletePod(
219+
client: ApolloClient<any>,
220+
ids: string[]
221+
) {
219222
const mutation = gql`
220-
mutation deletePod($id: String!, $toDelete: [String]) {
221-
deletePod(id: $id, toDelete: $toDelete)
223+
mutation deletePods($ids: [String]) {
224+
deletePods(ids: $ids)
222225
}
223226
`;
224227
await client.mutate({
225228
mutation,
226229
variables: {
227-
id,
228-
toDelete,
230+
ids,
229231
},
230232
});
231233
return true;

ui/src/lib/store/podSlice.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ function deletePod(set, get) {
300300
{ id }: { id: string }
301301
) => {
302302
const pods = get().pods;
303-
const toDelete: string[] = [];
303+
const ids: string[] = [];
304304

305305
// get all ids to delete. Gathering them here is easier than on the server
306306

@@ -309,13 +309,13 @@ function deletePod(set, get) {
309309
const dfs = (id) => {
310310
const pod = pods[id];
311311
if (pod) {
312-
toDelete.push(id);
312+
ids.push(id);
313313
pod.children.forEach(dfs);
314314
}
315315
};
316316

317317
dfs(id);
318-
// pop in toDelete
318+
// pop in ids
319319
set(
320320
produce((state: MyState) => {
321321
// delete the link to parent
@@ -326,13 +326,13 @@ function deletePod(set, get) {
326326
// remove all
327327
parent.children.splice(index, 1);
328328
}
329-
toDelete.forEach((id) => {
329+
ids.forEach((id) => {
330330
delete state.pods[id];
331331
});
332332
})
333333
);
334334
if (client) {
335-
await doRemoteDeletePod(client, { id, toDelete });
335+
await doRemoteDeletePod(client, ids);
336336
}
337337
};
338338
}

0 commit comments

Comments
 (0)