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

Pipe to emit a single issue #618

Closed
IlyaSemenov opened this issue May 31, 2024 · 3 comments
Closed

Pipe to emit a single issue #618

IlyaSemenov opened this issue May 31, 2024 · 3 comments
Assignees
Labels
enhancement New feature or request

Comments

@IlyaSemenov
Copy link
Contributor

As a developer, I would like to create reusable schemas, presumably with the new pipe function, that only emit a single issue to the parse result.

export function naturalNumber(message = "Natural value expected.") {
  return v.pipe(v.number(message), v.integer(message), v.minValue(1, message))
}

const schema = v.object({
  foo: naturalNumber(),
  bar: naturalNumber(),
  baz: naturalNumber(),
})

console.log(v.flatten(v.safeParse(schema, { foo: -1, bar: "nonsense", baz: -1.5 }).issues!))

delivers:

{
  nested: {
    foo: [ 'Natural value expected.' ],
    bar: [ 'Natural value expected.' ],
    baz: [ 'Natural value expected.', 'Natural value expected.' ]
  }
}

I'd somehow like baz to have only 1 issue. Note that parse(..., { abortPipeEarly: true }) is not really an option, as it's global to the whole parse and also it's controlled by the user (and not by the schema author).

Of course I could always fallback to custom() but then pipe() kinda loses its value.

Some ideas:

// new method:
v.abortEarlyPipe(schema, pipe1, ...)

// pipe config:
v.pipe(schema, pipe1, ..., config?: { abortEarly?: boolean })

// composition of pipe elements:
v.pipe(
  v.number(message),
  v.pipeItem(v.integer(message), v.minValue(1, message)),
  possiblyOtherPipeItemWithOwnMessage()
)
@fabian-hiller
Copy link
Owner

We could introduce an abortPipeEarly method that overwrites this config for all nested schemas:

export function naturalNumber(message = "Natural value expected.") {
  return v.abortPipeEarly(v.pipe(v.number(message), v.integer(message), v.minValue(1, message)));
}

An alternative could be a general config method that merges the new config into the previously applied config for all nested schemas:

export function naturalNumber(message = "Natural value expected.") {
  return v.config(v.pipe(v.number(message), v.integer(message), v.minValue(1, message)), { abortPipeEarly: true });
}

What do you think is best? Until this functionality is part of the library, you can write this method yourself:

export function abortPipeEarly<TSchema extends v.GenericSchema>(
  schema: TSchema
): TSchema {
  return {
    ...schema,
    _run(dataset, config) {
      return schema._run(dataset, { ...config, abortPipeEarly: true });
    },
  };
}

export function config<TSchema extends v.GenericSchema>(
  schema: TSchema,
  config: Omit<v.Config<v.InferIssue<TSchema>>, 'skipPipe'>
): TSchema {
  return {
    ...schema,
    _run(dataset, config_) {
      return schema._run(dataset, { ...config_, ...config });
    },
  };
}

@fabian-hiller fabian-hiller self-assigned this Jun 1, 2024
@fabian-hiller fabian-hiller added the enhancement New feature or request label Jun 1, 2024
@IlyaSemenov
Copy link
Contributor Author

Thanks for confirming that the use case is valid.

I suppose between the two options you suggest, v.config is better as being more flexible (and presumably abortPipeEarly can be then built on top of it).

@fabian-hiller
Copy link
Owner

v0.31.0-rc.10 with config method is available

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants