Creating an object with many relations using tRPC and Prisma

146 views Asked by At

first of all, I'm new to tRPC and fullstack development as a whole. I'm working on an web application which will display information on Markets (Local markets) and their vendors. Right now I'm struggling on creating the tRPC route which will create a market because one market has many relations.

This is what a Market Prisma Schema looks like:Market Schema

I'm creating an Admin Panel so Admins can create, edit, or delete a Market.

Question: How do I properly create this Market Object and edit it with all these relations since they are also optional but Admins can choose to include them in.

This is the current state of my tRPC Market Route, I figured that this may cause a problem since if transactions fail, the market will be created anyways.

export const marketRouter = router({
  getAllMarkets: publicProcedure.query(async () => {
    const markets = await db.market.findMany({});
    return markets;
  }),

  getMarket: publicProcedure
    .input(z.object({ marketId: z.string() }))
    .query(async ({ ctx, input }) => {
      const market = await db.market.findUnique({
        where: {
          id: input.marketId,
        },
      });
      return market;
    }),

  createMarket: publicProcedure
    .input(MarketSchema)
    .mutation(async ({ input }) => {
      try {
        const { businessHours, uniqueServices, microMap, ...marketData } =
          input;

        const market = await db.market.create({ data: marketData });

        const operations = [];

        if (microMap) {
          operations.push(
            db.microMap.create({
              data: {
                ...microMap,
                marketId: market.id,
              },
            })
          );
        }

        if (uniqueServices && uniqueServices.length > 0) {
          uniqueServices.forEach((service) => {
            operations.push(
              db.uniqueService.create({
                data: {
                  ...service,
                  marketId: market.id,
                },
              })
            );
          });
        }

        if (businessHours && businessHours.length > 0) {
          businessHours.forEach((businessHour) => {
            operations.push(
              db.businessHour.create({
                data: {
                  ...businessHour,
                  marketId: market.id,
                },
              })
            );
          });
        }

        await db.$transaction(operations);

        return market;
      } catch (e: any) {
        throw new TRPCError({
          code: "INTERNAL_SERVER_ERROR",
          message: e.message,
        });
      }
    }),
});
// Export type router type signature,
// NOT the router itself.
export type MarketRouter = typeof marketRouter;

This is what the MarketSchema (with Zod) looks like:

const MarketSchema = z.object({
  code: z.string().max(4),
  ownerId: z.string(),
  bannerId: z.string().optional(),
  name: z.string().max(150),
  name_th: z.string().max(150),
  telephone: z.string().max(20).optional(),
  homeTel: z.string().max(20).optional(),
  email: z.string().max(200).optional(),
  description: z.string().max(255),
  description_th: z.string().max(255),
  briefHistory: z.string().max(255),
  briefHistory_th: z.string().max(255),
  
  microMap: MicroMapSchema.optional(),
  uniqueServices: z.array(UniqueServiceSchema).optional(),
  businessHours: z.array(BusinessHourSchema).optional(),

  averageRatings: z.number().default(0.0),
  ratings: z.number().default(0),
  latitude: z.number(),
  longitude: z.number(),
  taxId: z.string().max(20).optional(),
  isVerified: z.boolean().default(false),
  status: z.nativeEnum(Status).default(Status.ACTIVE),
  remark: z.string().max(200).optional(),
});
0

There are 0 answers