zenstackhq / zenstack

Fullstack TypeScript toolkit that enhances Prisma ORM with flexible Authorization layer for RBAC/ABAC/PBAC/ReBAC, offering auto-generated type-safe APIs and frontend hooks.
https://zenstack.dev
MIT License
2.07k stars 88 forks source link

All zod model properties wrapped in z.ZodOptional #898

Closed tlancina closed 6 months ago

tlancina commented 9 months ago

Hello! I guess it's more of a question: is there a reason for all model properties to be optional? I just upgraded to 1.5.0 from 1.2.0 and it broke a few types. I filed it as a bug since already optional fields are marked as optional again.

1.2.0:

export declare const AccountSchema: z.ZodObject<{
    id: z.ZodString;
    type: z.ZodString;
    provider: z.ZodString;
    providerAccountId: z.ZodString;
    refresh_token: z.ZodOptional<z.ZodNullable<z.ZodString>>;
    access_token: z.ZodOptional<z.ZodNullable<z.ZodString>>;
    expires_at: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
    token_type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
    scope: z.ZodOptional<z.ZodNullable<z.ZodString>>;
    id_token: z.ZodOptional<z.ZodNullable<z.ZodString>>;
    session_state: z.ZodOptional<z.ZodNullable<z.ZodString>>;
}

1.5.0:

export declare const AccountSchema: z.ZodObject<{
    type: z.ZodOptional<z.ZodString>;
    id: z.ZodOptional<z.ZodString>;
    provider: z.ZodOptional<z.ZodString>;
    providerAccountId: z.ZodOptional<z.ZodString>;
    refresh_token: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
    access_token: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
    expires_at: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodNumber>>>;
    token_type: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
    scope: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
    id_token: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
    session_state: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
    user: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
    userId: z.ZodOptional<z.ZodString>;
}

Environment (please complete the following information):

I haven't had a chance to dig into why (or bisect what version exactly this happened at), just posting in case it's immediately clear. Will dig in more when I get a chance.

ymc9 commented 9 months ago

Hi @tlancina ,

Thanks for bringing this up. Let me provide some clarifications about the generated zod schemas.

The main schemas (as you showed above AccountSchema) are meant to represent the entity fetched with a prisma findXXX call. Since with Prisma you can load entities partially using "select" and "include", I feel it makes sense to mark all fields optional. There are two variant zod schemas generated:

It seems that when calling z.partial on a zod object, "nullish" fields are wrapped with multiple layers of ZodOptional typing. However, I didn't notice how this breaks things either at compile or at runtime.

Could you let me know about more specifics on the way it's broken to you? Thanks!

tlancina commented 9 months ago

Hey thanks for the explanation. My gut reaction is that if Zod is for validating data going in to Prisma, then something like partial should be opt in, but I don't feel particularly strongly about it (I can also equally call .required).

At the end of the day this is a nitpick - I don't have a good use case and wasn't even using it to validate input, I was using it to access Enum values as literals for the UI using .shape 😅 (and then had to .unwrap them).

ymc9 commented 9 months ago

Hey thanks for the explanation. My gut reaction is that if Zod is for validating data going in to Prisma, then something like partial should be opt in, but I don't feel particularly strongly about it (I can also equally call .required).

At the end of the day this is a nitpick - I don't have a good use case and wasn't even using it to validate input, I was using it to access Enum values as literals for the UI using .shape 😅 (and then had to .unwrap them).

Ok, I guess I haven't fully understood your scenario but it sounds like an interesting one 😄. Zod schemas are versatile and can be used for different things.

I agree with you that it's best let the user to call ".partial". Let me reopen this issue and think if a change in V2 should be made. Thanks!

ymc9 commented 6 months ago

Fixed in v2.0.0-beta.1