diff --git a/packages/project/src/db/breakpoints.ts b/packages/project/src/db/breakpoints.ts index 056ea01d65..fcd02a5bd1 100644 --- a/packages/project/src/db/breakpoints.ts +++ b/packages/project/src/db/breakpoints.ts @@ -4,6 +4,7 @@ import { applyPatches, type Patch } from "immer"; import { type Breakpoints as DbBreakpoints, prisma, + Prisma, } from "@webstudio-is/prisma-client"; import { type Breakpoint, Breakpoints } from "@webstudio-is/css-data"; @@ -33,9 +34,10 @@ export const createValues = () => export const create = async ( buildId: DbBreakpoints["buildId"], - values: Array + values: Array, + client: Prisma.TransactionClient = prisma ) => { - const breakpoints = await prisma.breakpoints.create({ + const breakpoints = await client.breakpoints.create({ data: { values: JSON.stringify(values), buildId, diff --git a/packages/project/src/db/build.ts b/packages/project/src/db/build.ts index 629a0d4bb1..71a0a896b2 100644 --- a/packages/project/src/db/build.ts +++ b/packages/project/src/db/build.ts @@ -1,4 +1,4 @@ -import { prisma, Build as DbBuild } from "@webstudio-is/prisma-client"; +import { prisma, Build as DbBuild, Prisma } from "@webstudio-is/prisma-client"; import { type Breakpoint } from "@webstudio-is/css-data"; import { v4 as uuid } from "uuid"; import * as db from "."; @@ -156,8 +156,14 @@ export const deletePage = async (buildId: Build["id"], pageId: Page["id"]) => { }); }; -const createPages = async (breakpoints: Array) => { - const tree = await db.tree.create(db.tree.createRootInstance(breakpoints)); +const createPages = async ( + breakpoints: Array, + client: Prisma.TransactionClient +) => { + const tree = await db.tree.create( + db.tree.createRootInstance(breakpoints), + client + ); return Pages.parse({ homePage: { id: uuid(), @@ -171,26 +177,36 @@ const createPages = async (breakpoints: Array) => { }); }; -const clonePage = async (source: Page) => { +const clonePage = async ( + source: Page, + client: Prisma.TransactionClient = prisma +) => { const treeId = source.treeId; - - const tree = await db.tree.clone(treeId); - await db.props.clone({ previousTreeId: treeId, nextTreeId: tree.id }); - + const tree = await db.tree.clone(treeId, client); + await db.props.clone({ previousTreeId: treeId, nextTreeId: tree.id }, client); return { ...source, id: uuid(), treeId: tree.id }; }; -const clonePages = async (source: Pages) => { +const clonePages = async ( + source: Pages, + client: Prisma.TransactionClient = prisma +) => { const clones = []; for (const page of source.pages) { - clones.push(await clonePage(page)); + clones.push(await clonePage(page, client)); } return Pages.parse({ - homePage: await clonePage(source.homePage), + homePage: await clonePage(source.homePage, client), pages: clones, }); }; +/* + * We create "dev" build in two cases: + * 1. when we create a new project + * 2. when we clone a project + * When create "prod" build when we publish a dev build. + */ export async function create( projectId: Build["projectId"], env: "prod", @@ -215,52 +231,38 @@ export async function create( if (count > 0) { throw new Error("Dev build already exists"); } - - const breakpointsValues = sourceBuild - ? (await db.breakpoints.load(sourceBuild.id)).values - : db.breakpoints.createValues(); - - const pages = - sourceBuild === undefined - ? await createPages(breakpointsValues) - : await clonePages(sourceBuild.pages); - - const build = await prisma.build.create({ - data: { - projectId, - pages: JSON.stringify(pages), - isDev: true, - isProd: false, - }, - }); - - await db.breakpoints.create(build.id, breakpointsValues); - - return; } - if (sourceBuild === undefined) { + if (env === "prod" && sourceBuild === undefined) { throw new Error("Source build required"); } - const breakpointsValues = (await db.breakpoints.load(sourceBuild.id)).values; + const breakpointsValues = sourceBuild + ? (await db.breakpoints.load(sourceBuild.id)).values + : db.breakpoints.createValues(); - const pages = await clonePages(sourceBuild.pages); + await prisma.$transaction(async (client) => { + const pages = + sourceBuild === undefined + ? await createPages(breakpointsValues, client) + : await clonePages(sourceBuild.pages); - const [, build] = await prisma.$transaction([ - prisma.build.updateMany({ - where: { projectId: projectId, isProd: true }, - data: { isProd: false }, - }), - prisma.build.create({ + if (env === "prod") { + await client.build.updateMany({ + where: { projectId: projectId, isProd: true }, + data: { isProd: false }, + }); + } + + const build = await client.build.create({ data: { projectId, pages: JSON.stringify(pages), - isDev: false, - isProd: true, + isDev: env === "dev", + isProd: env === "dev", }, - }), - ]); + }); - await db.breakpoints.create(build.id, breakpointsValues); + await db.breakpoints.create(build.id, breakpointsValues, client); + }); } diff --git a/packages/project/src/db/props.ts b/packages/project/src/db/props.ts index 6f37d840b0..0877deb09f 100644 --- a/packages/project/src/db/props.ts +++ b/packages/project/src/db/props.ts @@ -8,7 +8,7 @@ import { UserProps, } from "@webstudio-is/react-sdk"; import { applyPatches, type Patch } from "immer"; -import { prisma } from "@webstudio-is/prisma-client"; +import { prisma, Prisma } from "@webstudio-is/prisma-client"; import { formatAsset } from "@webstudio-is/asset-uploader/server"; const baseUserProps = { @@ -114,14 +114,17 @@ export const deleteByTreeId = async (treeId: Tree["id"]) => { await prisma.instanceProps.deleteMany({ where: { treeId } }); }; -export const clone = async ({ - previousTreeId, - nextTreeId, -}: { - previousTreeId: string; - nextTreeId: string; -}) => { - const props = await prisma.instanceProps.findMany({ +export const clone = async ( + { + previousTreeId, + nextTreeId, + }: { + previousTreeId: string; + nextTreeId: string; + }, + client: Prisma.TransactionClient | typeof prisma = prisma +) => { + const props = await client.instanceProps.findMany({ where: { treeId: previousTreeId }, }); if (props.length === 0) return; @@ -130,13 +133,17 @@ export const clone = async ({ treeId: nextTreeId, })); - await prisma.$transaction( + const create = async (client: Prisma.TransactionClient) => data.map((prop) => - prisma.instanceProps.create({ + client.instanceProps.create({ data: prop, }) - ) - ); + ); + + // If our client is not a transaction client, we need to create a transaction + "$transaction" in client + ? await client.$transaction(create) + : await create(client); }; export const patch = async ( diff --git a/packages/project/src/db/tree.ts b/packages/project/src/db/tree.ts index 09a8765b0d..efcf6ac52e 100644 --- a/packages/project/src/db/tree.ts +++ b/packages/project/src/db/tree.ts @@ -1,6 +1,6 @@ import { type Tree, Instance } from "@webstudio-is/react-sdk"; import { applyPatches, type Patch } from "immer"; -import { prisma } from "@webstudio-is/prisma-client"; +import { prisma, type Prisma } from "@webstudio-is/prisma-client"; import { Tree as DbTree } from "@prisma/client"; import { utils } from "../index"; import type { Breakpoint } from "@webstudio-is/css-data"; @@ -15,10 +15,13 @@ export const createRootInstance = (breakpoints: Array) => { return utils.tree.populateInstance(instance, defaultBreakpoint.id); }; -export const create = async (root: Instance): Promise => { +export const create = async ( + root: Instance, + client: Prisma.TransactionClient = prisma +): Promise => { Instance.parse(root); const rootString = JSON.stringify(root); - return await prisma.tree.create({ + return await client.tree.create({ data: { root: rootString }, }); }; @@ -27,8 +30,11 @@ export const deleteById = async (treeId: string): Promise => { await prisma.tree.delete({ where: { id: treeId } }); }; -export const loadById = async (treeId: string): Promise => { - const tree = await prisma.tree.findUnique({ +export const loadById = async ( + treeId: string, + client: Prisma.TransactionClient = prisma +): Promise => { + const tree = await client.tree.findUnique({ where: { id: treeId }, }); @@ -42,12 +48,15 @@ export const loadById = async (treeId: string): Promise => { }; }; -export const clone = async (treeId: string) => { - const tree = await loadById(treeId); +export const clone = async ( + treeId: string, + client: Prisma.TransactionClient = prisma +) => { + const tree = await loadById(treeId, client); if (tree === null) { throw new Error(`Tree ${treeId} not found`); } - return await create(tree.root); + return await create(tree.root, client); }; export const patch = async (