gcanti / tcomb-validation

Validation library based on type combinators
MIT License
400 stars 23 forks source link

Union of structs #38

Open SeeThruHead opened 8 years ago

SeeThruHead commented 8 years ago

should this be working?

const data = {
  text: 'whyoff'
};

const attributes = t.union([
  t.struct({ text: t.String }),
  t.struct({ url: t.String })
], 'Attributes');

const result = validate(data, attributes);

console.log(result);
=========================================
Struct {
  errors: 
   [ Struct {
       message: 'Invalid value {\n  "text": "whyoff"\n} supplied to Attributes',
       actual: [Object],
       expected: [Object],
       path: [] } ],
  value: { text: 'whyoff' } }
gcanti commented 8 years ago

Hi @SeeThruHead,

In case of union of structs you must implement a dispatch function (https://github.com/gcanti/tcomb/blob/master/docs/API.md#the-dispatch-function), since in general tcomb doesn't know which constructor to use:

const data = {
  text: 'whyoff'
}

const Text = t.struct({ text: t.String }, 'Text')
const Url = t.struct({ url: t.String }, 'Url')

const Attributes = t.union([
  Text,
  Url
], 'Attributes')

// dummy dispatch: given an input the dispatch function should return the suitable constructor
Attributes.dispatch = function (x) {
  return x.text ? Text : Url
}

const result = t.validate(data, Attributes)

console.log(result)

// => Struct {errors: Array[0], value: Object} // OK!
SeeThruHead commented 8 years ago

Oh I see, I had thought that validate would run through until it found one that matched. Thanks again!

--  Shane Keulen Sent with Airmail

On March 14, 2016 at 1:50:31 PM, Giulio Canti (notifications@github.com) wrote:

const data = { text: 'whyoff' }

const Text = t.struct({ text: t.String }, 'Text') const Url = t.struct({ url: t.String }, 'Url')

const Attributes = t.union([ Text, Url ], 'Attributes')

// dummy dispatch: given an input the dispatch function should return the suitable constructor Attributes.dispatch = function (x) { return x.text ? Text : Url }

const result = t.validate(data, Attributes)

console.log(result)

ferndopolis commented 8 years ago

👍 this was helpful and might want to add to the readme today i ran into a problem where the variable which is initalize as null and must be a number between a range, but am using custom error messages. here's the code

const mysubtype = (type, getValidationErrorMessage, name) => {
  let Subtype = t.subtype(type, (x) => {
    return !t.String.is(getValidationErrorMessage(x));
  }, name);
  Subtype.getValidationErrorMessage = getValidationErrorMessage;
  return Subtype;
}

const notNull = mysubtype(t.Nil, (s) => {
  if (!s) return 'Required';
});

const cap = mysubtype(t.Number, (s) => {
  if (!s) return 'Required';
  if (s <= 1) return 'Must be greater than one';
  if (s > 25) return 'Cannot be greater than 25';
});

export const Capacity = t.union([notNull, cap], 'Capacity');
Capacity.dispatch = (x) => { return x ? cap : notNull };