-
Notifications
You must be signed in to change notification settings - Fork 0
feat: update test flow schema and remove two unnecessary test flow tables #18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| /* | ||
| Warnings: | ||
|
|
||
| - You are about to drop the column `checkpoint_url` on the `test_flows` table. All the data in the column will be lost. | ||
| - You are about to drop the column `is_clipped` on the `test_flows` table. All the data in the column will be lost. | ||
| - You are about to drop the `test_flow_compositions` table. If the table is not empty, all the data it contains will be lost. | ||
| - You are about to drop the `test_flow_steps` table. If the table is not empty, all the data it contains will be lost. | ||
|
|
||
| */ | ||
| -- DropForeignKey | ||
| ALTER TABLE "test_flow_compositions" DROP CONSTRAINT "test_flow_compositions_flow_id_fkey"; | ||
|
|
||
| -- DropForeignKey | ||
| ALTER TABLE "test_flow_compositions" DROP CONSTRAINT "test_flow_compositions_step_id_fkey"; | ||
|
|
||
| -- DropForeignKey | ||
| ALTER TABLE "test_flow_steps" DROP CONSTRAINT "test_flow_steps_crawl_session_id_fkey"; | ||
|
|
||
| -- AlterTable | ||
| ALTER TABLE "test_flows" DROP COLUMN "checkpoint_url", | ||
| DROP COLUMN "is_clipped", | ||
| ADD COLUMN "transition_refs" TEXT[]; | ||
|
|
||
| -- DropTable | ||
| DROP TABLE "test_flow_compositions"; | ||
|
|
||
| -- DropTable | ||
| DROP TABLE "test_flow_steps"; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| # Please do not edit this file manually | ||
| # It should be added in your version-control system (i.e. Git) | ||
| # It should be added in your version-control system (e.g., Git) | ||
| provider = "postgresql" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,24 +5,13 @@ | |
| import prisma from "@lib/prisma"; | ||
| import { logger } from "@services/logger.service"; | ||
|
|
||
| interface FlowStep { | ||
| state_hash: string; | ||
| transition: Record<string, unknown> | null; | ||
| } | ||
|
|
||
| interface SerializedFlow { | ||
| checkpoint: string; | ||
| is_clipped: boolean; | ||
| path: FlowStep[]; | ||
| transition_refs: string[]; | ||
| } | ||
|
|
||
| export type AllFlowsPayload = Record<string, SerializedFlow[]>; | ||
|
|
||
| function resolveCheckpointUrl(flow: SerializedFlow): string { | ||
| const firstAction = flow.path[1]; | ||
| return (firstAction?.transition?.checkpoint_url as string | undefined) ?? ""; | ||
| } | ||
|
|
||
| export async function saveAllFlows( | ||
| sessionId: string, | ||
| payload: AllFlowsPayload, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SerializedFlow and AllFlowsPayload may be redundant after adding the contracts and just using the same contract you will use for the schema as a type here. |
||
|
|
@@ -32,111 +21,27 @@ export async function saveAllFlows( | |
| select: { appVersionId: true }, | ||
| }); | ||
|
|
||
| const stepsByFingerprint = new Map<string, { | ||
| sourceStateHash: string; | ||
| targetStateHash: string; | ||
| actionType: string; | ||
| actionFingerprint: string; | ||
| transition: Record<string, unknown>; | ||
| }>(); | ||
|
|
||
| for (const flows of Object.values(payload)) { | ||
| for (const flow of flows) { | ||
| for (let i = 1; i < flow.path.length; i++) { | ||
| const step = flow.path[i]; | ||
| const prev = flow.path[i - 1]; | ||
| const t = step.transition; | ||
|
|
||
| if (!t) continue; | ||
|
|
||
| const fingerprint = t.action_fingerprint as string | undefined; | ||
| if (!fingerprint || stepsByFingerprint.has(fingerprint)) continue; | ||
|
|
||
| stepsByFingerprint.set(fingerprint, { | ||
| sourceStateHash: prev.state_hash, | ||
| targetStateHash: step.state_hash, | ||
| actionType: (t.action_type as string) ?? "", | ||
| actionFingerprint: fingerprint, | ||
| transition: t, | ||
| }); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| const stepsToInsert = Array.from(stepsByFingerprint.values()).map((s) => ({ | ||
| crawlSessionId: sessionId, | ||
| sourceStateHash: s.sourceStateHash, | ||
| targetStateHash: s.targetStateHash, | ||
| actionType: s.actionType, | ||
| actionFingerprint: s.actionFingerprint, | ||
| transition: s.transition as any, | ||
| })); | ||
|
|
||
| if (stepsToInsert.length > 0) { | ||
| await prisma.testFlowStep.createMany({ | ||
| data: stepsToInsert, | ||
| skipDuplicates: true, | ||
| }); | ||
| } | ||
|
|
||
| const persistedSteps = await prisma.testFlowStep.findMany({ | ||
| where: { crawlSessionId: sessionId }, | ||
| select: { id: true, actionFingerprint: true }, | ||
| const flowsToInsert = Object.entries(payload).flatMap(([targetStateHash, flows]) => { | ||
| return flows.map((flow) => ({ | ||
| crawlSessionId: sessionId, | ||
| appVersionId: session.appVersionId, | ||
| targetStateHash, | ||
| checkpointStateHash: flow.checkpoint, | ||
| transitionRefs: flow.transition_refs, | ||
| stepCount: flow.transition_refs.length, | ||
| })); | ||
| }); | ||
|
|
||
| const stepIdByFingerprint = new Map( | ||
| persistedSteps.map((s) => [s.actionFingerprint, s.id]), | ||
| ); | ||
|
|
||
| const allDbOperations: Array<ReturnType<typeof prisma.testFlow.create>> = []; | ||
|
|
||
| for (const [targetStateHash, flows] of Object.entries(payload)) { | ||
| if (flows.length === 0) continue; | ||
|
|
||
| for (const flow of flows) { | ||
| const compositionSteps: { stepId: string; stepOrder: number }[] = []; | ||
|
|
||
| for (let i = 1; i < flow.path.length; i++) { | ||
| const step = flow.path[i]; | ||
| const fingerprint = step.transition?.action_fingerprint as string | undefined; | ||
|
|
||
| if (fingerprint) { | ||
| const stepId = stepIdByFingerprint.get(fingerprint); | ||
| if (stepId) { | ||
| compositionSteps.push({ | ||
| stepId, | ||
| stepOrder: i, | ||
| }); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| allDbOperations.push( | ||
| prisma.testFlow.create({ | ||
| data: { | ||
| crawlSessionId: sessionId, | ||
| appVersionId: session.appVersionId, | ||
| targetStateHash, | ||
| checkpointStateHash: flow.checkpoint, | ||
| checkpointUrl: resolveCheckpointUrl(flow), | ||
| isClipped: flow.is_clipped, | ||
| stepCount: flow.path.length, | ||
| compositions: { | ||
| create: compositionSteps, | ||
| }, | ||
| }, | ||
| }) | ||
| ); | ||
| } | ||
| if (flowsToInsert.length === 0) { | ||
| logger.info(`No flows to save for session ${sessionId}`); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be an error and add a constants file for the errors/messages. |
||
| return; | ||
| } | ||
|
|
||
| if (allDbOperations.length > 0) { | ||
| await prisma.$transaction(allDbOperations); | ||
| } | ||
| await prisma.testFlow.createMany({ | ||
| data: flowsToInsert, | ||
| }); | ||
|
|
||
| logger.info( | ||
| `Saved flows for session ${sessionId}: ` + | ||
| `${stepsByFingerprint.size} unique steps, ` + | ||
| `${Object.values(payload).flat().length} total flows`, | ||
| `Saved flows for session ${sessionId}: ${flowsToInsert.length} total flows saved in bulk.`, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Return a |
||
| ); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Schemas should be a contract in the
coverit-contractsand added to themodels/folder instead of creating them using zod.