Added typed lists support
This commit is contained in:
parent
e39691763f
commit
e938a814e8
|
@ -4,8 +4,10 @@
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var jutil = require('./jutil');
|
var jutil = require('./jutil');
|
||||||
var Validatable = require('./validatable').Validatable;
|
var Validatable = require('./validatable').Validatable;
|
||||||
|
var List = require('./list');
|
||||||
var Hookable = require('./hookable').Hookable;
|
var Hookable = require('./hookable').Hookable;
|
||||||
var DEFAULT_CACHE_LIMIT = 1000;
|
var DEFAULT_CACHE_LIMIT = 1000;
|
||||||
|
var BASE_TYPES = ['String', 'Boolean', 'Number', 'Date', 'Text'];
|
||||||
|
|
||||||
exports.AbstractClass = AbstractClass;
|
exports.AbstractClass = AbstractClass;
|
||||||
|
|
||||||
|
@ -61,10 +63,16 @@ AbstractClass.prototype._initProperties = function (data, applySetters) {
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
|
|
||||||
if (properties[attr].type.name === 'JSON' && this[_attr]) {
|
var type = properties[attr].type;
|
||||||
|
|
||||||
|
if (BASE_TYPES.indexOf(type.name) === -1) {
|
||||||
try {
|
try {
|
||||||
this[_attr] = JSON.parse(this[_attr] + '');
|
this[_attr] = JSON.parse(this[_attr] + '');
|
||||||
} catch (e) { }
|
if (type.name === 'Array' || typeof type === 'object' && type.constructor.name === 'Array') {
|
||||||
|
this[_attr] = new List(this[_attr], type, this);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public setters and getters
|
// Public setters and getters
|
||||||
|
@ -526,11 +534,19 @@ AbstractClass.prototype.toObject = function (onlySchema) {
|
||||||
var properties = ds.properties;
|
var properties = ds.properties;
|
||||||
// weird
|
// weird
|
||||||
Object.keys(onlySchema ? properties : this).concat(['id']).forEach(function (property) {
|
Object.keys(onlySchema ? properties : this).concat(['id']).forEach(function (property) {
|
||||||
data[property] = this[property];
|
if (this[property] instanceof List) {
|
||||||
|
data[property] = this[property].toObject();
|
||||||
|
} else {
|
||||||
|
data[property] = this[property];
|
||||||
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AbstractClass.prototype.toJSON = function () {
|
||||||
|
return this.toObject();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete object from persistence
|
* Delete object from persistence
|
||||||
*
|
*
|
||||||
|
|
|
@ -503,6 +503,7 @@ MySQL.prototype.propertySettingsSQL = function (model, prop) {
|
||||||
function datatype(p) {
|
function datatype(p) {
|
||||||
var dt = '';
|
var dt = '';
|
||||||
switch (p.type.name) {
|
switch (p.type.name) {
|
||||||
|
default:
|
||||||
case 'String':
|
case 'String':
|
||||||
case 'JSON':
|
case 'JSON':
|
||||||
dt = 'VARCHAR(' + (p.limit || 255) + ')';
|
dt = 'VARCHAR(' + (p.limit || 255) + ')';
|
||||||
|
|
|
@ -515,6 +515,7 @@ function escape(val) {
|
||||||
|
|
||||||
function datatype(p) {
|
function datatype(p) {
|
||||||
switch (p.type.name) {
|
switch (p.type.name) {
|
||||||
|
default:
|
||||||
case 'String':
|
case 'String':
|
||||||
case 'JSON':
|
case 'JSON':
|
||||||
return 'varchar';
|
return 'varchar';
|
||||||
|
|
|
@ -177,6 +177,10 @@ BridgeToRedis.prototype.forDb = function (model, data) {
|
||||||
for (var i in data) {
|
for (var i in data) {
|
||||||
if (p[i] && p[i].type.name === 'Date') {
|
if (p[i] && p[i].type.name === 'Date') {
|
||||||
data[i] = data[i] && data[i].getTime ? data[i].getTime() : 0;
|
data[i] = data[i] && data[i].getTime ? data[i].getTime() : 0;
|
||||||
|
} else if (p[i] && [
|
||||||
|
'String', 'Text', 'Number', 'Boolean', 'Date'
|
||||||
|
].indexOf(p[i].type.name) === -1) {
|
||||||
|
data[i] = JSON.stringify(data[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
|
@ -193,6 +197,12 @@ BridgeToRedis.prototype.fromDb = function (model, data) {
|
||||||
data[i] = new Date();
|
data[i] = new Date();
|
||||||
data[i].setTime(ms);
|
data[i].setTime(ms);
|
||||||
}
|
}
|
||||||
|
} else if (p[i] && [
|
||||||
|
'String', 'Text', 'Number', 'Boolean', 'Date'
|
||||||
|
].indexOf(p[i].type.name) === -1) {
|
||||||
|
try {
|
||||||
|
data[i] = JSON.parse(data[i]);
|
||||||
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
|
||||||
|
module.exports = List;
|
||||||
|
|
||||||
|
function List(data, type, parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.nextid = 1;
|
||||||
|
data = this.items = data || [];
|
||||||
|
var Item = this.ItemType = ListItem;
|
||||||
|
|
||||||
|
if (typeof type === 'object' && type.constructor.name === 'Array') {
|
||||||
|
this.ItemType = Item = type[0] || ListItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.forEach(function (item) {
|
||||||
|
data[i] = new Item(item, parent);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
List.prototype.toObject = function () {
|
||||||
|
return this.items;
|
||||||
|
};
|
||||||
|
|
||||||
|
List.prototype.autoincrement = function () {
|
||||||
|
return this.nextid++;
|
||||||
|
};
|
||||||
|
|
||||||
|
List.prototype.push = function (obj) {
|
||||||
|
var item = new ListItem(obj, this);
|
||||||
|
if (this.ItemType) {
|
||||||
|
item.__proto__ = this.ItemType.prototype;
|
||||||
|
}
|
||||||
|
item.id = this.autoincrement();
|
||||||
|
this.items.push(item);
|
||||||
|
return item;
|
||||||
|
};
|
||||||
|
|
||||||
|
List.prototype.remove = function (obj) {
|
||||||
|
var found;
|
||||||
|
this.items.forEach(function (o, i) {
|
||||||
|
if (o.id === obj.id) found = i;
|
||||||
|
});
|
||||||
|
if (found) {
|
||||||
|
this.items.splice(i, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
List.prototype.forEach = function (cb) {
|
||||||
|
this.items.forEach(cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
List.prototype.sort = function (cb) {
|
||||||
|
return this.items.sort(cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
List.prototype.map = function (cb) {
|
||||||
|
if (typeof cb === 'function') return this.items.map(cb);
|
||||||
|
if (typeof cb === 'string') return this.items.map(function (el) {
|
||||||
|
if (typeof el[cb] === 'function') return el[cb]();
|
||||||
|
if (el.hasOwnProperty(cb)) return el[cb];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function ListItem(data, parent) {
|
||||||
|
for (var i in data) this[i] = data[i];
|
||||||
|
Object.defineProperty(this, 'parent', {
|
||||||
|
writable: false,
|
||||||
|
enumerable: false,
|
||||||
|
configurable: true,
|
||||||
|
value: parent
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -181,7 +181,10 @@ Schema.prototype.define = function defineClass(className, properties, settings)
|
||||||
function standartize(properties, settings) {
|
function standartize(properties, settings) {
|
||||||
Object.keys(properties).forEach(function (key) {
|
Object.keys(properties).forEach(function (key) {
|
||||||
var v = properties[key];
|
var v = properties[key];
|
||||||
if (typeof v === 'function') {
|
if (
|
||||||
|
typeof v === 'function' ||
|
||||||
|
typeof v === 'object' && v && v.constructor.name === 'Array'
|
||||||
|
) {
|
||||||
properties[key] = { type: v };
|
properties[key] = { type: v };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "jugglingdb",
|
"name": "jugglingdb",
|
||||||
"description": "ORM for every database: redis, mysql, neo4j, mongodb, postgres, sqlite",
|
"description": "ORM for every database: redis, mysql, neo4j, mongodb, postgres, sqlite",
|
||||||
"version": "0.1.16",
|
"version": "0.1.17",
|
||||||
"author": "Anatoliy Chakkaev <rpm1602@gmail.com>",
|
"author": "Anatoliy Chakkaev <rpm1602@gmail.com>",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
{ "name": "Anatoliy Chakkaev", "email": "rpm1602@gmail.com" },
|
{ "name": "Anatoliy Chakkaev", "email": "rpm1602@gmail.com" },
|
||||||
|
|
|
@ -77,9 +77,16 @@ function testOrm(schema) {
|
||||||
title: { type: String, length: 255, index: true },
|
title: { type: String, length: 255, index: true },
|
||||||
content: { type: Text },
|
content: { type: Text },
|
||||||
date: { type: Date, default: function () { return new Date }, index: true },
|
date: { type: Date, default: function () { return new Date }, index: true },
|
||||||
published: { type: Boolean, default: false }
|
published: { type: Boolean, default: false },
|
||||||
|
likes: [],
|
||||||
|
related: [RelatedPost]
|
||||||
}, {table: 'posts'});
|
}, {table: 'posts'});
|
||||||
|
|
||||||
|
function RelatedPost() { }
|
||||||
|
RelatedPost.prototype.someMethod = function () {
|
||||||
|
return this.parent;
|
||||||
|
};
|
||||||
|
|
||||||
Post.validateAsync('title', function (err, done) {
|
Post.validateAsync('title', function (err, done) {
|
||||||
process.nextTick(done);
|
process.nextTick(done);
|
||||||
});
|
});
|
||||||
|
@ -154,7 +161,7 @@ function testOrm(schema) {
|
||||||
|
|
||||||
it('should be expoted to JSON', function (test) {
|
it('should be expoted to JSON', function (test) {
|
||||||
test.equal(JSON.stringify(new Post({id: 1, title: 'hello, json', date: 1})),
|
test.equal(JSON.stringify(new Post({id: 1, title: 'hello, json', date: 1})),
|
||||||
'{"id":1,"title":"hello, json","content":null,"date":1,"published":false,"userId":null}');
|
'{"id":1,"title":"hello, json","content":null,"date":1,"published":false,"likes":[],"related":[],"userId":null}');
|
||||||
test.done();
|
test.done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -800,6 +807,15 @@ function testOrm(schema) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should work with typed and untyped nested collections', function (test) {
|
||||||
|
var post = new Post;
|
||||||
|
var like = post.likes.push({foo: 'bar'});
|
||||||
|
test.equal(like.constructor.name, 'ListItem');
|
||||||
|
var related = post.related.push({hello: 'world'});
|
||||||
|
test.ok(related.someMethod);
|
||||||
|
test.done();
|
||||||
|
});
|
||||||
|
|
||||||
it('all tests done', function (test) {
|
it('all tests done', function (test) {
|
||||||
test.done();
|
test.done();
|
||||||
process.nextTick(allTestsDone);
|
process.nextTick(allTestsDone);
|
||||||
|
|
Loading…
Reference in New Issue