Skip to content
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

Request for Enhancement: Support for Multiple Keys in variant Function #458

Closed
JolianGof opened this issue Feb 27, 2024 · 4 comments
Closed
Assignees
Labels
question Further information is requested

Comments

@JolianGof
Copy link

JolianGof commented Feb 27, 2024

Request for Enhancement: Support for Multiple Keys in variant Function

Hello Valibot Team,

I've been exploring Valibot for schema validation in my project and find it to be an invaluable tool for ensuring data integrity and type safety. However, I've encountered a scenario where I need to validate data based on multiple keys, rather than just one, using the variant function. I understand that the current implementation of the variant function supports validation based on a single discriminator key.

In my application, I'm dealing with complex data structures that require validation based on a combination of keys. Specifically, I need to validate data based on both type and email fields, where the validation schema varies depending on the combination of these two fields. While I'm aware that the variant function can be used to create nested schemas for complex validation scenarios, I've found that this approach significantly increases the complexity of my validation logic, making it more difficult to manage and understand.

Proposed Solution:

I'm proposing that the variant function be enhanced to support validation based on multiple keys. This would allow for more straightforward and readable validation logic, enabling developers to handle complex data structures more effectively without the need for deeply nested schemas.

Here's a conceptual example of how this could be implemented:


const VariantSchema = variant(['type', 'email'], [
  object({
    type: literal('email'),
    email: literal('a@gmail.com'),
    urls: array(string())
  }),
  object({
    type: literal('url'),
    email: literal('a@yahoo.com'),
    urls: Picklist(['https://', 'https://this.com'])
  }),
  object({
    type: literal('date'),
    email: literal('a@outlook.com'),
    ips: Picklist(['12.2.2.2', '2.2.2.2']),
    date: string([isoDate()])
  }),
]);

In this example, the variant function would select the appropriate schema based on the combination of type and email fields, rather than just one key. This approach would simplify the validation logic and make it easier to manage complex validation scenarios.

Request:

I kindly request your consideration of this feature request. If there's an existing solution or workaround for this scenario, I would appreciate being directed towards it. Alternatively, if you're considering adding this feature to Valibot, I believe it would greatly enhance the library's capabilities and usability for developers dealing with complex data structures.

Thank you for your time and consideration. I look forward to any feedback or discussions on this matter.

@fabian-hiller
Copy link
Owner

Thank you for creating this issue. What is the difference with multiple keys? It already works the way you want if you specify only one key. Check it out in our playground.

import * as v from 'valibot';

const VariantSchema = v.variant('type', [
  v.object({
    type: v.literal('email'),
    email: v.literal('a@gmail.com'),
    urls: v.array(v.string([v.url()])),
  }),
  v.object({
    type: v.literal('url'),
    email: v.literal('a@yahoo.com'),
    url: v.picklist(['https://', 'https://this.com']),
  }),
  v.object({
    type: v.literal('date'),
    email: v.literal('a@outlook.com'),
    ip: v.picklist(['12.2.2.2', '2.2.2.2']),
    date: v.string([v.isoDate()]),
  }),
]);

@fabian-hiller fabian-hiller self-assigned this Feb 28, 2024
@fabian-hiller fabian-hiller added the question Further information is requested label Feb 28, 2024
@JolianGof
Copy link
Author

I want to apologize for any confusion my previous message may have caused. Upon further reflection, I realize that the example I provided did not accurately represent the complexity of my use case, particularly concerning the handling of null values within the variant schema . n my project, I am dealing with a complex form that has numerous cases, each dependent on specific conditions. These conditions are not just based on a single discriminator key but require a combination of keys to determine the correct validation schema. This complexity is crucial for my application, as it needs to accurately validate data based on multiple criteria.

this is fake example

import * as v from 'valibot';

// Define the userType variant schema
const userType = v.variant('userType',[
 v.object({
    userType: v.literal('administrator'),
    requirement: v.array(v.string())
 }),
 v.object({
    userType: v.literal('user'),
    description: v.string()
 })
]);

// Define the typeEmails variant schema
const typeEmails = v.variant('email',[
 v.object({
    email: v.literal('a@gmail.com'),
    expired: v.date()
 }),
 v.object({
    email: v.literal('b@gmail.com'),
    description: v.string()
 })
]);

// Define the typeUrl variant schema
const typeUrl = v.variant('url',[
 v.object({
    url: v.literal('https://a.com'),
    domainName: v.string()
 }),
 v.object({
    url: v.literal('https://b.com'), // Corrected the typo here
    description: v.string()
 })
]);

// Define the VariantSchema that combines multiple conditions and handles null values
const VariantSchema = v.variant(['type', 'email'], [
 v.object({
    type: v.literal('email'),
    urls: v.array(v.string([v.url()])),
    email: v.literal('a@gmail.com'),
    // Include typeEmails.entries for more complex validation scenarios
    // Note: This is a conceptual example, as direct usage like this might not be supported
    // Consider using custom validation logic or nested schemas for complex scenarios
 }),
 v.object({
    type: v.literal('url'),
    email: v.literal('a@yahoo.com'),
    url: v.picklist(['https://', 'https://this.com']),
 }),
 v.object({
    type: v.literal('date'),
    email: v.literal('a@outlook.com'),
    ip: v.picklist(['12.2.2.2', '2.2.2.2']),
    date: v.string([v.isoDate()]),
 }),
 // Adding an object to handle null values for type
 v.object({
    type: v.literal(null), // This is crucial for handling null values
    email: v.string([v.email()]), // This field can be any string or null
    url: v.string([v.url()]), // This field can be any URL or null
 }),
]);

@fabian-hiller
Copy link
Owner

It looks like union is the right schema for your use case:

@fabian-hiller
Copy link
Owner

It is now possible to deeply nest multiple variant schemas to achieve this goal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants