diegohaz / schm

Composable schemas for JavaScript and Node.js

Home Page:https://git.io/schm

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[translate][suggestion] Use chaining instead of passing as param

itaditya opened this issue · comments

I saw the code snippet

const userSchema = schema({
  name: String,
  email: String,
}, translate({
  email: "emails.0",
}));

One thing that bugged me was the passing of translate to schema function as a positional parameter. From my personal experience I have found that this method doesn't do well in long term. I suggest using chaining method to extend the functionality like so -

const userSchema = schema({
  name: String,
  email: String,
}).translate({
  email: "emails.0",
})

Libraries like moment, jQuery all use this pattern, I can dig up some solid advantages if you like

@diegohaz here are some advantages -

  • more functional
  • less cognitive load

Maggie Pint, maintainer of Moment.js speaks about it in her talk

commented

I see value on that, but I'm not sure if I like it.

The first problem I see is: how can someone build a plugin for schm without adding it to the library itself (I mean, adding the method to the chain)?

The answer could be, instead of adding methods directly do the chain, to have a .plugin method where you pass the plugin as an argument:

schema({...}).plugin(translate({...})).plugin(query({...}))

But I don't know if that's really better than what we have today, which is, in my opinion, more straightforward:

schema({...}, translate({...}), query({...}))

The schema method is intended to be kind of compose. Actually, that was its name when I was first writing the library.

You can think of schema this way (and this is actually possible 😄: https://runkit.com/diegohaz/schm-schm-schm-schm):

schema(schema(), schema(schema(schema()), schema()))

The literal object you pass to schema is actually a shorthand to this:

schema(group({...}))

group returns a schema, translate returns a schema. So everything still makes sense. Maybe what we need to do is to make it more clear in the docs.

That said, that's extremely easy to create a custom schema with chainable methods:

const schm = require('schm')
const translate = require('schm-translate')

const withTranslate = prevSchema => prevSchema.merge({
  translate(...args) {
    return schm(this, translate(...args))
  }
})

const schema = params => schm(params, withTranslate)

const userSchema = schema({
  name: String,
  email: String,
}).translate({
  email: "emails.0",
})

See the above snippet working: https://runkit.com/diegohaz/chainable-schm