# moldy

> A javascript model API for the browser + server that is actually worth using.

Latest version **2.5.2** (published 2016-01-11) · MIT license · 0 weekly downloads

## Install

```sh
npm install moldy
pnpm add moldy
yarn add moldy
bun add moldy
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 2.5.2 |
| Published | 2016-01-11 |
| First published | 2014-03-31 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 8 |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | David Tsuji, Pierre Derval, Glen Arrowsmith, Ash Kyd |
| Maintainers | davidtsuji, garrows, dervalp |

## Links

- npm: https://www.npmjs.com/package/moldy
- Repository: https://github.com/moldy/moldy
- Homepage: http://moldy.io
- Issues: https://github.com/moldy/moldy/issues
- npm.io page: https://npm.io/package/moldy

## Dependencies (8)

- [clone](https://npm.io/package/clone.md) ^1.0.2
- [sc-is](https://npm.io/package/sc-is.md) 0.0.3
- [sc-cast](https://npm.io/package/sc-cast.md) 2.0.0
- [sc-guid](https://npm.io/package/sc-guid.md) 0.0.4
- [sc-merge](https://npm.io/package/sc-merge.md) 1.0.1
- [sc-haskey](https://npm.io/package/sc-haskey.md) 0.0.2
- [emitter-component](https://npm.io/package/emitter-component.md) ^1.1.1
- [sg-observable-array](https://npm.io/package/sg-observable-array.md) 0.0.2

## Recent versions

- 2.5.2 (latest) — 2016-01-11
- 2.5.1 — 2016-01-11
- 2.5.0 — 2015-11-30
- 2.4.0 — 2015-11-26
- 2.3.0 — 2015-11-26
- 2.2.0-0 — 2015-11-26
- 2.1.3 — 2015-10-21
- 2.1.2 — 2015-07-21
- 2.1.1 — 2015-07-21
- 2.1.0 — 2015-07-13
- 2.0.0 — 2015-07-10
- 1.3.6 — 2015-03-11
- 1.3.5 — 2014-11-06
- 1.3.4 — 2014-11-06
- 1.3.3 — 2014-11-06
- … 38 more at https://npm.io/package/moldy/versions

## README

# TOC
   - [moldy](#moldy)
     - [Property Attributes](#moldy-property-attributes)
       - [Type & default](#moldy-property-attributes-type--default)
       - [Optional](#moldy-property-attributes-optional)
       - [Arrays of a type](#moldy-property-attributes-arrays-of-a-type)
     - [A model's url aka endpoint](#moldy-a-models-url-aka-endpoint)
     - [find](#moldy-find)
     - [save](#moldy-save)
     - [destroy](#moldy-destroy)
<a name=""></a>
 
<a name="moldy"></a>
# moldy
Create a Moldy.

```js
var personMoldy = Moldy.extend( 'person' )
	.$property( 'id' )
	.$property( 'name' )
	.$property( 'age' )
	.create();
personMoldy.should.have.a.property( 'id', undefined );
personMoldy.should.have.a.property( 'name', undefined );
personMoldy.should.have.a.property( 'age', undefined );
```

<a name="moldy-property-attributes"></a>
## Property Attributes
<a name="moldy-property-attributes-type--default"></a>
### Type & default
Properties can by strongly typed. If a type has been defined, values are cast to that type automatically. If a value cannot be cast to a type then the value will be set to `null` or the `default` if it has been defined.

```js
var personMoldy = Moldy.extend( 'person', {
				properties: {
					'age': 'number',
					'active': {
						type: 'boolean',
						default: false
					},
					'tags': 'array'
				}
			} ).create();
			/**
			 * When a model's properties have been `typed` the assigned values are cast on the fly
			 * to ensure the model's data remains sanitized.
			 */
			/**
			 * Cast a `string` for `age` to a `number`
			 */
			personMoldy.age = '13';
			personMoldy.age.should.equal( 13 ).and.be.an.instanceOf( Number );
			/**
			 * Cast a truthy `string` for `active` as a `boolean`
			 */
			personMoldy.active = 'yes';
			personMoldy.active.should.equal( true ).and.be.an.instanceOf( Boolean );
			/**
			 * `active` is typed as a `boolean` _and_ a `default` has been defined. When an
			 * assigned value that cannot be cast as a `boolean` is set then the `default` will
			 * apply.
			 */
			personMoldy.active = 'this is not a boolean';
			should( personMoldy.active ).equal( false ).and.be.an.instanceOf( Boolean );
			/**
			 * Cast a `string` for `tags` as an `array`
			 */
			personMoldy.tags = 'lorem';
			should( personMoldy.tags ).eql( [ 'lorem' ] ).and.be.an.instanceOf( Array );
```

<a name="moldy-property-attributes-optional"></a>
### Optional
Properties can be optional. By making a property optional, `isValid()` and `toJson()` will ignore it if is has not been set.

```js
var personMoldy = Moldy.extend( 'person' )
	.$property( 'id' )
	.$property( 'name' )
	.$property( 'age', {
		type: 'number',
		optional: true
	} )
	.$property( 'active', {
		type: 'boolean',
		default: false
	} )
	.$property( 'tags', {
		type: 'array',
		optional: true
	} )
	.create();
/**
 * To ensure this `person` is valid we only need to set the `id` and `name` because
 * the other keys are either `optional` or have `defaults`.
 */
personMoldy.id = 1;
personMoldy.name = 'David';
personMoldy.$isValid().should.be.ok;
```

<a name="moldy-property-attributes-arrays-of-a-type"></a>
### Arrays of a type
A property can be defined as `array` of a type like an `array` of `strings`, or an `array` of `numbers`.

```js
var personMoldy = Moldy.extend( 'person' )
	.$property( 'id' )
	.$property( 'tags', {
		type: [ 'string' ]
	} )
	.create();
/**
 * When defining an array of a type, the arrays are normal arrays however they have been
 * extended to allow hooks into the necessary methods for sanitization.
 */
personMoldy.tags.should.be.an.Array;
personMoldy.tags.should.have.a.property( 'length' ).and.be.a.Number;
personMoldy.tags.should.have.a.property( 'pop' ).and.be.a.Function;
personMoldy.tags.should.have.a.property( 'push' ).and.be.a.Function;
personMoldy.tags.should.have.a.property( 'reverse' ).and.be.a.Function;
personMoldy.tags.should.have.a.property( 'shift' ).and.be.a.Function;
personMoldy.tags.should.have.a.property( 'sort' ).and.be.a.Function;
personMoldy.tags.should.have.a.property( 'splice' ).and.be.a.Function;
personMoldy.tags.should.have.a.property( 'unshift' ).and.be.a.Function;
/**
 * Pushing a value - like normal
 */
personMoldy.tags.push( 'yellow' );
/**
 * We are pushing a `number` here to show how the value will be cast to a string
 */
personMoldy.tags.push( 1 );
/**
 * The value `1` is now a string
 */
personMoldy.tags[ 1 ].should.equal( '1' );
personMoldy.tags.should.have.a.lengthOf( 2 );
personMoldy.tags.should.eql( [ 'yellow', '1' ] );
/**
 * A gotcha for using primitive types in this context is that they are not sanitized
 * based on the schema if they are changed directly
 */
personMoldy.tags[ 1 ] = 1;
/**
 * Technically this should have cast the number `1` to a string but it was a design
 * decision not to add getters/setters to each item in an array. A santize method will
 * be added in the next version
 */
personMoldy.tags[ 1 ].should.equal( 1 );
```

Array types can also be model schemas.

```js
var personMoldy = Moldy.extend( 'person' )
	.$property( 'cars', {
		type: [ {
			name: 'car',
			properties: {
				make: 'string',
				model: {
					type: 'string',
					default: ''
				},
				year: 'number'
			}
		} ]
	} )
	.create();
/**
 * Note, we are missing the `model` key and the `year` is a string
 */
personMoldy.cars.push( {
	make: 'honda',
	year: '2010'
} );
personMoldy.cars[ 0 ].$json().should.eql( {
	id: undefined,
	make: 'honda',
	model: '',
	year: 2010
} );
```

<a name="moldy-a-models-url-aka-endpoint"></a>
## A model's url aka endpoint
A url (endpoint) is automatically generated based on the `Moldy` name, key, `$url()` and `$baseUrl()`.

```js
var Person = Moldy.extend( 'person', {
	baseUrl: '/api'
} );
var personMoldy = Person.create();
Person.$url().should.eql( '/api/person' );
/**
 * The url can be changed using either `base()` or `url()`
 */
Person.$url( 'v1' );
Person.$url().should.eql( '/api/person/v1' );
```

<a name="moldy-find"></a>
## find
To find by `id` or `key`, give an object with appropriate conditions.

```js
var personMoldy = Moldy.extend( 'person', {
	key: 'guid',
	properties: {
		name: ''
	}
} );
personMoldy.$findOne( {
	guid: '5f55821f-3a28-45c3-b91d-7df927a863d8'
}, function ( _error, _res ) {
	if ( _error ) {
		return _done( _error );
	}
	_done();
} );
```

If an adapter responds with an array the first item will be returned.

```js
var Person = Moldy.extend( 'person', {
	key: 'guid',
	properties: {
		name: ''
	}
} );
/**
 * In this example the end point GET `http://localhost:3000/api` returns an array of items.
 * Moldy will return the first item out of the array. If you need to return an array you can
 * use the $collection method.
 */
Person.$findOne( function ( _error, _res ) {
	if ( _error ) {
		return _done( _error );
	}
	_res.should.not.be.an.Array;
	_done();
} );
```

<a name="moldy-find"></a>
## find
To find an array of models.

```js
var Person = Moldy.extend( 'person', {
	key: 'guid',
	properties: {
		name: 'string'
	}
} );
Person.$find( function ( _error, _people ) {
	if ( _error ) {
		return _done( _error );
	}
	_people.should.be.an.Array().with.a.lengthOf( 3 );
	_people.forEach( function ( _person ) {
		_person.should.be.a.Moldy;
	} );
	_done();
} );
```

<a name="moldy-save"></a>
## save
To save the model, call `save()`. If the model is `dirty` (has not been saved to the server and therefore does not have a valid `key`) then the http method will be POST. If the model has been saved, then the http method will be PUT.

```js
var personMoldy = Moldy.extend( 'person', {
	properties: {
		name: 'string'
	}
} ).create();
personMoldy.name = 'David';
personMoldy.$save( function ( _error, _res ) {
	if ( _error ) {
		return _done( _error );
	}
	personMoldy.$json().should.eql( _res.$json() );
	personMoldy.should.have.a.property( 'id' );
	personMoldy.name = 'Mr David';
	personMoldy.$save( function ( _error, _res ) {
		personMoldy.should.eql( _res );
		_done( _error );
	} );
} );
```

<a name="moldy-destroy"></a>
## destroy
To destroy a model, call `destroy()`.

```js
var personMoldy = Moldy.extend( 'person', {
	key: 'guid',
	properties: {
		name: 'string'
	}
} ).create();
personMoldy.name = 'David';
personMoldy.$save( function ( _error, _res ) {
	if ( _error ) {
		return _done( _error );
	}
	personMoldy.$destroy( function ( _error, _res ) {
		personMoldy.$isDirty().should.be.true;
		//personMoldy.$isValid().should.be.false; -- DO NOT GET WHY SHOULD BE FALSE
		//personMoldy.__destroyed.should.be.true;
		_done( _error );
	} );
} );
```

---
_Source: https://npm.io/package/moldy · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
