Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/Kikobeats/osom

An Awesome [/osom/] Object Data Modeling (Database Agnostic).
https://github.com/Kikobeats/osom

casting schema transformations

Last synced: about 2 months ago
JSON representation

An Awesome [/osom/] Object Data Modeling (Database Agnostic).

Awesome Lists containing this project

README

        

# osom

> An Awesome [/osom/] Object Data Modeling. Inspired in [mongoose ](https://github.com/Automattic/mongoose#defining-a-model) but Database Agnostic.

![Last version](https://img.shields.io/github/tag/Kikobeats/osom.svg?style=flat-square)
[![Coverage Status](https://img.shields.io/coveralls/Kikobeats/osom.svg?style=flat-square)](https://coveralls.io/github/Kikobeats/osom)
[![NPM Status](https://img.shields.io/npm/dm/osom.svg?style=flat-square)](https://www.npmjs.org/package/osom)

## Installation

```bash
$ npm install osom --save
```

## Preview

```js
const osom = require('osom')

function trim (str) {
return str.trim()
}

function isValidTitle (str) {
return str.length > 0
}

// setup your schema
const schema = {
title: {
type: String,
validate: isValidTitle,
transform: [trim]
},
category: String,
type: String,
source: String,
link: String,
createdAt: String,
updatedAt: String
}

// create validator based on schemas
const validator = osom(schema)

// validate it!
validator({ title: ' 23 ' }) // => {title: '23'}
```

## Usage

osom(schema, [global])

where:

- `schema`: It represents a set of rules (one per each key) that will be used for validate an object.
- `global` (optional): It brings you the possibility to declare global rules definition as helper to avoid write repetitive code.

After that, you will have a validator `function` that you can invoke passing the object to be validate.

## Schema

### Simple

The most common use case is validate the `type` of something.

If you are only interested in the `type`, you can provide a simple schema like:

```js
const simpleSchema = {
age: Number
}
```

Where `key` is the name of the rule and `value` the `type` of it.

### Advanced

The *basic* mode is a simplification of the *advanced* mode for the most common use case.

While in *basic* mode only is possible setup `type`, in *advanced* mode you can setup more things providing a configurable `object`.

Each key of the object represent a **rule** . It's possible setup different things in the same rule.

## Defining Rules

### type

Type: `function`

As in *basic* mode, it specifies the `type` of the output value:

```js
const schema = {
age: {
type: Number
}
}
```

Internally it uses [chaste](https://github.com/Kikobeats/chaste). This makes easy casting compatible types:

```js
const schema = {
age: {
type: Number
}
}

const validator = osom(schema)
validator({ age: '23' }) // => {age: 23}
```

### casting

Type: `boolean`

Default: `true`

It enable/disable type casting.
An `TypeError` will be throwed under different `type` evaluation.

```js
const schema = {
age: {
type: String,
casting: false
}
}

const validator = osom(schema)
validator({ age: '23' }) // => TypeError("Expected a {string} for 'age'.")
```

### required

Type: `boolean`|`string`

Default: `false`

It marks a rule as required field and throws `TypeError` if value for the field is not present.

Additionally is possible provide a custom error message. For do it, pass an `String`.

```js
const schema = {
age: {
type: String,
required: 'sorry but you must provide an age.'
}
}

const validator = osom(schema)
validator({}) // => TypeError("sorry but you must provide an age")
```

### default

Type: `string`|`object`|`number`|`boolean`|`function`

Default: `null`

It sets a default value if `nill` value as input is provided.

Additionally you can provide a `function` for set a dynamic value:

```js
const schema = {
age: {
type: Number, default: function () { return 23 }
}
}

const validator = osom(schema)
validator({}) // => { age: 23 }
```

### transform

Type: `function`|`array`

Default: `[]`

It transforms the input value.

The Methods provided in the `array` are applied as pipeline (the input of the second is the output of the first).

```js
function trim (str) {
return str.trim()
}

const schema = {
age: {
type: String,
transform: [trim]
}
}

const validator = osom(schema)
validator({ age: ' 23 ' }) // => { age: '23' }
```

### validate

Type: `function`|`object`

Default: `null`

It set up a `function` that will be exec to validate the input value.
If it fails, it throws `TypeError`.

```js
const schema = {
age: {
type: String,
validate: function (v) {
return v === '23'
}
}
}

const validator = osom(schema)
validator({ age: 25 }) // => TypeError("Fail '25' validation for 'age'.")
```

Providing a object brings you the possibility set up a custom error message:

```js
const schema = {
age: {
type: String,
validate: {
validator: function (v) {
return v === '23'
},
message: 'expected a millenial value instead of %s!'
}
}
}

const validator = osom(schema)
validator({ age: 25 }) // => TypeError("expected a millenial value instead of 25!")
```

## Defining Global Rules

While is possible provide specific setup per each rule, also is possible provide them as global to apply to all rules.

This minimizes the schemas definitions.

```js
function trim (str) {
return str.trim()
}

const schema = {
age: {
type: String
}
}

const globalFields = {
transform: [trim]
}

const validator = osom(schema, globalFields)
validator({ age: ' 23 ' }) // => {age: '23'}
```

No problem if later you need to avoid it for a specific case.

```js
function trim (str) {
return str.trim()
}

const schema = {
age: {
type: String,
transform: []
}
}

const globalFields = {
transform: [trim]
}

const validator = osom(schema, globalFields)
validator({ age: ' 23 ' }) // => {age: ' 23 '}
```

## Tips

### Working with async code

This library works synchronously.

However, you can use it comfortably in a async workflow transforming the interface into a callback/promise style.

For example, consider use [async#asyncify](https://github.com/caolan/async#asyncify) for do it. we could have a `schema.js` file like:

```js
const schema = osom({
title: {
type: String,
validate: isValidTitle,
transform: [trim]
},
category: String,
type: String,
source: String,
link: String,
createdAt: String,
updatedAt: String
})

module.exports = async.asyncify(schema)
module.exports.sync = schema
```

Then you only need use it into a async workflow:

```js
const schema = require('./schema')
schema(data, function (validationError, instance) {
/** do something */
})
```

Be careful: this transformation doesn't mean that the function works now asynchronously; Just is converting
`try-catch` interface into `callback(err, data)`.

## License

MIT © [Kiko Beats](https://kikobeats.com)