andreww2012 / mongoose-zod

A library which allows to author mongoose ("a MongoDB object modeling tool") schemas using zod ("a TypeScript-first schema declaration and validation library").
MIT License
49 stars 7 forks source link

Using mongoose-zod with superforms #6

Closed soupman99 closed 9 months ago

soupman99 commented 1 year ago

I'm working with superforms and mongoose. When I use the config in the readme I see the error: Error: Only Zod schema objects can be used with superValidate. Define the schema with z.object({ ... }) and optionally refine/superRefine/transform at the end.

Any idea on how to get these 2 to play nicely together?

andreww2012 commented 1 year ago

Hey @soupman99 can I see your code?

soupman99 commented 1 year ago

@andreww2012 thanks for the reply!

Here's my file. It's a little messy, but here's what I'm working with. I also included regular zod schema I got working with superforms (newContactSchema).

import {z} from 'zod';
import { fail } from "@sveltejs/kit"

import {superValidate, setError} from 'sveltekit-superforms/server'
/** @type {import('./$types').PageServerLoad} */
import {genTimestampsSchema, toMongooseSchema, mongooseZodCustomType} from 'mongoose-zod';

import * as M from 'mongoose'

//this is a schema I have working with superforms
const newContactSchema = z.object({
    firstName:z.string().min(5),
    lastName:z.string().min(4),
    email: z.string().email().min(4),
    company:z.string().optional(),
    // _id: z.string().optional()
})

//this is the schema I'm experiementing with
 const userZodSchema = z
  .object({
    // Sub schema
    info: z.object({
      // Define type options like this (NOT recommended - better to use `typeOptions` passed to `.mongoose()` - see FAQ)
      // [instead `.mongooseTypeOptions()`, you may use `addMongooseTypeOptions` if you opt out of extending zod prototype]
    //   nickname: z.string().min(1).mongooseTypeOptions({unique: true}),
      birthday: z.tuple([
        z.number().int().min(1900),
        z.number().int().min(1).max(12),
        z.number().int().min(1).max(31),
      ]),
      // Unlike mongoose, arrays won't have an empty array `[]` as a default value!
      friends: z.number().int().min(1).array().optional(),
      // Making the field optional
      status: z.enum(['😊', '😔', '🤔']).optional(),
      // Use this function to use special (Buffer, ObjectId, ...) and custom (Long, ...) types
      avatar: mongooseZodCustomType('Buffer'),
    }),
    // Default values set with zod's .default() are respected
    regDate: z.date().default(new Date()),
  })
  // Schema merging supported natively by zod. We make use of this feature
  // by providing a schema generator for creating type-safe timestamp fields
  .merge(genTimestampsSchema('crAt', 'upAt'))
  // Define schema options here:
  // [instead `.mongoose()`, you may use `toZodMongooseSchema` if you opt out of extending zod prototype]
  .mongoose({
    schemaOptions: {
      collection: 'users',

      // Full type safety in virtuals, as well as in statics, methods and query methods
      virtuals: {
        bday: {
          get() {
            const [y, m, d] = this.info.birthday;
            return new Date(y, m - 1, d);
          },
          set(d: Date) {
            this.info.birthday = [d.getFullYear(), d.getMonth() + 1, d.getDate()];
          },
        },
      },

    },

    // Ability to override type schema options
    typeOptions: {
      upAt: {
        index: false,
      },
    },
  });

//test out schema
const UserSchema = toMongooseSchema(userZodSchema, {});

const User = M.model('User', UserSchema);

const user = new User().toJSON();

//working superforms validation code
export async function load(event) {
    const form  = await superValidate(event, newContactSchema)
    return {
        form
    }

}

export const actions = {
    //working version of 
    default: async (event) => {
        const form = await superValidate(event, newContactSchema)
        if (!form.valid) {
            return fail(400, {
                form
            })
        }else{
             return { form }
        }
    }
}
andreww2012 commented 1 year ago

@soupman99 sorry, but from your example it's not clear what you are trying to do that produces that error. Are you trying to pass the result of toMongooseSchema call to superValidate? If so, then it won't work because toMongooseSchema returns a mongoose schema, but superValidate expects a zod schema.

andreww2012 commented 9 months ago

I'm closing this since there are no issues with mongoose-zod here. You'll likely need to pass a schema to superforms before calling .mongoose() on it.