npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

moldy

v2.5.2

Published

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

Downloads

41

Readme

TOC

moldy

Create a Moldy.

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 );

Property Attributes

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.

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 );

Optional

Properties can be optional. By making a property optional, isValid() and toJson() will ignore it if is has not been set.

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;

Arrays of a type

A property can be defined as array of a type like an array of strings, or an array of numbers.

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.

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 model's url aka endpoint

A url (endpoint) is automatically generated based on the Moldy name, key, $url() and $baseUrl().

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' );

find

To find by id or key, give an object with appropriate conditions.

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.

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();
} );

find

To find an array of models.

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();
} );

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.

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 );
	} );
} );

destroy

To destroy a model, call destroy().

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 );
	} );
} );