ClassJS
Business and Data Access layers for browsers or nodejs
Documentation
Install
- NodeJS
- Standalone:
$ npm install atma-class
var Class = require('atma-class')
- AtmaPackage
- Browser
<script src='//cdn.jsdelivr.net/classjs/1.0.66/class.min.js'></script>
Attributes
Class definition object is a simple prototype
object, but with Attributes
it is possible to add or change some functionality of the resulted class, like inheritance, overrides, persistance, validation and some more.
Class({
Base: < Function > BaseConstructor,
Extends: < Function | Object | Array > Mixins
Construct: < Function > function(){}
Static: < Object > { key: function(){} }
Store: <| Class.Remote('/user/:id')
| Class.LocalStore('user')
| Class.MongoStore.Single('users')
| Class.MongoStore.Collection('users') |>
Override: < Object > {
some: function(){
this.super(arguments);
this.super(arg1, arg2);
}
},
Self: {
foo: function(){}
},
Validate: {
user: function(val){
if (val == null)
return 'Username is not defined';
}
},
'_property': null,
...
});
Serialization
A Class
instance can be serialized to or deserialiazed from a string or simple JSON object. For this to happen, the instance schould be inherited from a Serialization
class.
var Foo = Class({
Base: Class.Serializable,
...
});
var foo = new Foo({baz: 'Baz'});
foo.baz === 'Baz';
There could be also some meta specified
var Foo = Class({
Base: Class.Serializable({
'date': Date,
'article': 'Article',
'user': {
deserialize: User
},
'none': {
serialize: null
},
'myKey': {
key: 'yourKey'
}
})
});
var jsonStr = '{"date":"2014-03-27T23:33:45.594Z","user":{"name":"baz"},"yourKey":5}';
var foo = new Foo(jsonStr);
foo.date instanceof Date
foo.user instanceof User
foo.myKey === 5
Collections
Creates Array-like Object with all class features
var Users = Class.Collection(User, {
Store: Class.Remote('/api/users?location={?country}')
});
var list = Users
.fetch({country: 'DE'});
.done(function(obj){
list === obj
list.length
list[0]
list.first({age: '>20', genre: 'm'});
list.where({age: '>20'});
list.where(function(x){ return x.age > 20 });
list.remove({age: '<5'});
list.save();
list.del({age: '<5'});
});
Store
Storage Interface is same for all types, so you can easily switch between local storage, Ajax or MongoDB.
Remote
async - extends Class.Deferred
var User = Class({
Base: Class.Serializable,
Store: Class.Remote('/user/:id')
});
var user = User
.fetch({id: 5})
.done(onSuccess)
.fail(onFail)
.always(onComplete)
.then(onSuccess, onFail);
user.name = 'X';
user
.save()
.done(onSuccess)
.fail(onFail)
.always(onComplete);
user
.del()
.done(onSuccess)
.fail(onFail)
.always(onComplete)
user
.patch({
$inc: { 'visits': 1 },
$set: { 'current.date' : new Date }
});
var user = new User({
username: 'baz'
age: 40
});
Class
.Remote
.send('/user/publish', 'put', user)
.done(function(responseJSON){
});
More route samples can be found from tests Route Tests
LocalStore
sync, as localStorage is synchronous - but also inherits from Class.Deferred
var Settings = Class({
Base: Class.Serializable,
Store: Class.LocalStore('app/settings'),
points: 5
});
var setts = new Settings;
setts.fetch();
setts.points = 10;
setts.save();
setts.del();
setts.patch({
$inc: { points: 1 }
});
MongoDB
Class.MongoStore.settings({
db: 'myDBName',
ip: '127.0.0.1'
port: 27017
});
var User = Class({
Base: Class.Serializable,
Store: Class.MongoStore.Single('users'),
username: ''
});
var Users = Class.Collection(User, {
Store: Class.MongoStore.Collection('users')
});
var user = User
.fetch({ username: 'bar' })
.done(function(user_){
user === user_
})
.fail(function(error){})
Users
.fetch({
$query:{
name: 'Smith'
age: {
$gte: 40
}
},
$orderby:{
surname: -1
}
}, {
fields: { name: 1 },
skip: 0,
limit: 10
})
.done(function(users){});
user.username = 'foo'
user
.save()
.done(callback)
.fail(callback)
.always(callback)
;
user
.del()
.done(callback)
.fail(callback)
.always(callback);
user
.patch({
$inc: { age: 1 }
});
Class
.MongoStore
.resolveDb()
.done(function(db){
})
.fail(onError);
User
.resolveCollection()
.done(function(collection){
})
.fail(onError)
;
All work with the database is encapsulated, so you do not need even to connect to the database,
just apply settings and with the first query the connection will be established.
Indexes
var User = Class({
Base: Class.Serializable,
Store: Class.MongoStore.Single({
collection: 'users',
indexes: [
{ qux: 1}
{
bar: 1,
baz: 1
},
[{ username: 1 }, { unique: true }]
]
})
});
Class
.MongoStore
.ensureIndexes(User)
Class
.MongoStore
.ensureIndexesAll()
Advanced connections and settings:
Class
.MongoStore
.settings({
connection: 'mongodb://localhost:30000,localhost:30001,localhost:30002/myDatabase',
params: {
auto_reconnect: true,
native_parser: true,
w: 1
}
})
Profiler
Enable profiler to catch all slow, unindexed queries and updates.
Class
.MongoStore
.profiler
.toggle(true, {
slowLimit: 200,
onDetect: function(QueryInfo),
detector: function(MongoDB_Plan):Boolean
});
QueryInfo = {
coll: 'String `current name`',
query: 'Object `query wich was performed`',
params: {
reason: '`slow|unindexed`'
},
plan: MongoDB_Plan
};
Class
.MongoStore
.profiler
.getData(): Array<QueryInfo>
Repository
Namespaces When declaring a Class, it can be stored in the repository object for simpler access.
MaskJS.Node profits of this feature to automatically serialize (server-side) and deserialize (browser) class instances.
var User = Class('User', ClassDefinition);
User === Class('User') === Class.Model.User;
Class.cfg('ModelHost', window.Model = {});
User === Class('User') === Model.User;
Static Functions
-
Class.validate(object [, ?validationModel, ?isStrict])
#
validationModel
- (@see Validation) - is not required, if instance/object has Validate
attribute.isStrict
- Boolean - return error if object contains property, which is not defined in validationModel
returns error object if the instance is invalid or nothing (void 0
) if is ok.
-
Class.properties(Ctor | instance)
#
return hash of all properties with types if known.
-
Class.keys(instance)
#
return array of properties (without methods and private props)
-
Class.stringify(instance)
#
Serializes the instance. If class has name, the name is included, for later deserialization and initialization
-
Class.parse(string)
#
Deserializes instance. e.g - serialize models on NodeJS, pass them to the front-end and restore the models there.
var User = Class('User', {
Base: Class.Serializable,
name: '',
log: function(){ console.log(this.name) };
});
var user = new User({name: 'baz'});
user.log();
var str = Class.stringify(user)
...
var user = Class.parse(str);
user.log()
Validation
Validation Model
{
foo: 'string',
foo: 'number',
age: /^\d+$/,
number: function(value){
if (value % 2 !== 0)
return 'Only even numbers';
}
'?baz': 'number',
'-quz': null,
jokers: {
left: 'number',
right: 'number'
},
collection: [ {_id: 'string', username: 'string'} ]
}
-
Class Validation
var Foo = Class({
Validate: ValidationModel
});
var foo = new Foo;
var error = Class.validate(foo);
-
Simple object validation
var user = { username: 'foo' }
var error = Class.validate(user, ValidationModel);
Classes
There are some classes you can start to use.
Deferred
Promise
/Defer
implementation
Usage example
var X = Class({
Base: Class.Deferred,
});
var dfr = new X;
var dfr = new Class.Deferred;
var dfr = Class.Deferred.run(function(dfr){
});
var fn = Class.Deferred.create(function(dfr, foo){
dfr.resolve(foo);
}));
var dfr = fn('foo');
var fn = Class.Deferred.memoize(function(dfr, foo){
dfr.resolve(foo);
}));
var dfr1 = fn('foo');
var dfr2 = fn('foo');
dfr1 === dfr2;
Deferred __proto__ {
done : function(callback):Self,
fail : function(callback):Self,
always: function(callback):Self,
resolve: function(...args):Self,
reject : function(...args):Self
defer : function():Self
pipe : Function
= function(Deferred):Self
= function(doneFilter, failFilter): new Deferred
pipeCallback: function(): function
then : function(doneFilter, dailFilter):new Deferred,
isResolved: function():Boolean,
isRejected: function():Boolean
isBusy : function():Boolean
};
doneFilter/failFilter : Function
= function(): Any
= function(): Deferred
Deferred __static__ {
create: function(fn:function):Function,
run: function(fn:function):Deferred,
memoize: function(fn:function):Deferred
};
EventEmitter
var X = Class({
Extends: Class.EventEmitter,
});
new X();
new Class.EventEmitter;
EventEmitter __proto__ {
emit: function(...args):Self,
trigger: function(...args):Self,
on: function(event, callback):Self,
once: function(event, callback):Self,
off: function(event, callback):Self,
pipe: function(event): function
}
Run tests and build
$ npm install
$ npm test
$ atma
(c) 2014 MIT