From 12a624d99c2d4602c41d20a817435747a6397602 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Thu, 13 Feb 2014 23:42:21 -0800 Subject: [PATCH] Rewrite the List class for typed array --- examples/inclusion.js | 15 +-- examples/nesting-schema.js | 1 + lib/dao.js | 11 +- lib/datasource.js | 3 - lib/list.js | 251 +++++++++---------------------------- lib/types.js | 104 +++++++-------- 6 files changed, 120 insertions(+), 265 deletions(-) diff --git a/examples/inclusion.js b/examples/inclusion.js index cf15df82..4fe57ff9 100644 --- a/examples/inclusion.js +++ b/examples/inclusion.js @@ -24,20 +24,7 @@ setup(function () { }); User.find({include: ['posts', 'passports']}, function (err, users) { - // console.log('users.passports && users.posts', users); - users.forEach(function (user) { - console.log('user', user); - user.posts(function (err, posts) { - if (posts && posts.length > 0) { - console.log('posts', posts); - } - }); - user.passports(function (err, passports) { - if (passports && passports.length > 0) { - console.log('posts', passports); - } - }); - }); + console.log('users.passports && users.posts', users); }); }); diff --git a/examples/nesting-schema.js b/examples/nesting-schema.js index 3ae83684..899e4e7c 100644 --- a/examples/nesting-schema.js +++ b/examples/nesting-schema.js @@ -29,4 +29,5 @@ var user = new User({name: 'Joe', age: 20, address: {street: '123 Main St', 'cit {label: 'work', email: 'xyz@sample.com'} ], friends: ['John', 'Mary']}); +console.log(user); console.log(user.toObject()); diff --git a/lib/dao.js b/lib/dao.js index 7f62dc45..3314790f 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -6,13 +6,12 @@ module.exports = DataAccessObject; /** * Module dependencies */ -var util = require('util'); var jutil = require('./jutil'); var validations = require('./validations.js'); var ValidationError = validations.ValidationError; -require('./relations.js'); -var Inclusion = require('./include.js'); var Relation = require('./relations.js'); +var Inclusion = require('./include.js'); +var List = require('./list.js'); var geo = require('./geo'); var Memory = require('./connectors/memory').Memory; var utils = require('./utils'); @@ -562,7 +561,11 @@ DataAccessObject.find = function find(params, cb) { } includes.forEach(function (inc) { // Promote the included model as a direct property - obj.__data[inc] = obj.__cachedRelations[inc]; + var data = obj.__cachedRelations[inc]; + if(Array.isArray(data)) { + data = new List(data, data[0] && [data[0].constructor], obj); + } + obj.__data[inc] = data; }); delete obj.__data.__cachedRelations; } diff --git a/lib/datasource.js b/lib/datasource.js index 356a58c9..a709a0b4 100644 --- a/lib/datasource.js +++ b/lib/datasource.js @@ -7,11 +7,8 @@ var jutil = require('./jutil'); var utils = require('./utils'); var ModelBaseClass = require('./model.js'); var DataAccessObject = require('./dao.js'); -var List = require('./list.js'); var EventEmitter = require('events').EventEmitter; var util = require('util'); -var path = require('path'); -var fs = require('fs'); var assert = require('assert'); var async = require('async'); diff --git a/lib/list.js b/lib/list.js index b5be01ad..d679d570 100644 --- a/lib/list.js +++ b/lib/list.js @@ -1,154 +1,75 @@ +var util = require('util'); + module.exports = List; -/** - * List class provides functionality of nested collection - * - * @param {Array} data - array of items. - * @param {Crap} type - array with some type information? TODO: rework this API. - * @param {AbstractClass} parent - owner of list. - * @constructor - */ -function List(data, type, parent) { +function List(items, itemType, parent) { var list = this; if (!(list instanceof List)) { - return new List(data, type, parent); + return new List(items, itemType, parent); } - if (typeof data === 'string') { + if (typeof items === 'string') { try { - data = JSON.parse(data); + items = JSON.parse(items); } catch (e) { - throw new Error('could not create List from JSON string: ', data); + throw new Error('could not create List from JSON string: ', items); } } - if (data && data instanceof List) data = data.items; + var arr = []; + arr.__proto__ = List.prototype; - Object.defineProperty(list, 'parent', { - writable: false, - enumerable: false, - configurable: false, - value: parent - }); + items = items || []; + if (!Array.isArray(items)) { + throw new Error('Items must be an array: ' + items); + } - Object.defineProperty(list, 'nextid', { + if(!itemType) { + itemType = items[0] && items[0].constructor; + } + + if (Array.isArray(itemType)) { + itemType = itemType[0]; + } + + Object.defineProperty(arr, 'itemType', { writable: true, enumerable: false, - value: 1 + value: itemType }); - data = list.items = data || []; - var Item = list.ItemType = ListItem; - - if (typeof type === 'object' && type.constructor.name === 'Array') { - Item = list.ItemType = type[0] || ListItem; - } - - data.forEach(function (item, i) { - data[i] = Item(item, list); - Object.defineProperty(list, data[i].id, { + if (parent) { + Object.defineProperty(arr, 'parent', { writable: true, enumerable: false, - configurable: true, - value: data[i] + value: parent }); - if (list.nextid <= data[i].id) { - list.nextid = data[i].id + 1; - } - }); - - Object.defineProperty(list, 'length', { - enumerable: false, - configurable: true, - get: function () { - return list.items.length; - } - }); - - return list; - -} - -var _; -try { - var underscore = 'underscore'; - _ = require(underscore); -} catch (e) { - _ = false; -} - -if (_) { - var _import = [ - // collection methods - 'each', - 'map', - 'reduce', - 'reduceRight', - 'find', - 'filter', - 'reject', - 'all', - 'any', - 'include', - 'invoke', - 'pluck', - 'max', - 'min', - 'sortBy', - 'groupBy', - 'sortedIndex', - 'shuffle', - 'toArray', - 'size', - // array methods - 'first', - 'initial', - 'last', - 'rest', - 'compact', - 'flatten', - 'without', - 'union', - 'intersection', - 'difference', - 'uniq', - 'zip', - 'indexOf', - 'lastIndexOf', - 'range' - ]; - - _import.forEach(function (name) { - List.prototype[name] = function () { - var args = [].slice.call(arguments); - args.unshift(this.items); - return _[name].apply(_, args); - }; - }); -} - -['slice', 'forEach', 'filter', 'reduce', 'map'].forEach(function (method) { - var slice = [].slice; - List.prototype[method] = function () { - return Array.prototype[method].apply(this.items, slice.call(arguments)); - }; -}); - -List.prototype.find = function (pattern, field) { - if (field) { - var res; - this.items.forEach(function (o) { - if (o[field] == pattern) res = o; - }); - return res; - } else { - return this.items[this.items.indexOf(pattern)]; } + + items.forEach(function (item, i) { + if (itemType && !(item instanceof itemType)) { + arr[i] = itemType(item); + } else { + arr[i] = item; + } + }); + + return arr; +} + +util.inherits(List, Array); + +var _push = List.prototype.push; + +List.prototype.push = function (obj) { + var item = this.itemType && (obj instanceof this.itemType) ? obj : this.itemType(obj); + _push.call(this, item); + return item; }; List.prototype.toObject = function (onlySchema) { var items = []; - this.items.forEach(function (item) { + this.forEach(function (item) { if (item.toObject) { items.push(item.toObject(onlySchema)); } else { @@ -163,75 +84,15 @@ List.prototype.toJSON = function () { }; List.prototype.toString = function () { - return JSON.stringify(this.items); + return JSON.stringify(this.toJSON()); }; -List.prototype.autoincrement = function () { - return this.nextid++; -}; - -List.prototype.push = function (obj) { - var item = new ListItem(obj, this); - this.items.push(item); - return item; -}; - -List.prototype.remove = function (obj) { - var id = obj.id ? obj.id : obj; - var found = false; - this.items.forEach(function (o, i) { - if (id && o.id == id) { - found = i; - if (o.id !== id) { - console.log('WARNING! Type of id not matched'); - } - } - }); - if (found !== false) { - delete this[id]; - this.items.splice(found, 1); - } -}; - -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) { - if (!(this instanceof ListItem)) { - return new ListItem(data, parent); - } - if (typeof data === 'object') { - for (var i in data) this[i] = data[i]; - } else { - this.id = data; - } - Object.defineProperty(this, 'parent', { - writable: false, - enumerable: false, - configurable: true, - value: parent - }); - if (!this.id) { - this.id = parent.autoincrement(); - } - if (parent.ItemType) { - this.__proto__ = parent.ItemType.prototype; - if (parent.ItemType !== ListItem) { - parent.ItemType.apply(this); - } - } - - this.save = function (c) { - parent.parent.save(c); - }; -} +/* + var strArray = new List(['1', 2], String); + strArray.push(3); + console.log(strArray); + console.log(strArray.length); + console.log(strArray.toJSON()); + console.log(strArray.toString()); + */ diff --git a/lib/types.js b/lib/types.js index e5dbcc1a..7c35adce 100644 --- a/lib/types.js +++ b/lib/types.js @@ -1,44 +1,48 @@ -module.exports = function (Types) { +var Types = {}; +/** + * Schema types + */ +Types.Text = function Text(value) { + if (!(this instanceof Text)) { + return value; + } + this.value = value; +}; // Text type + +Types.Text.prototype.toObject = Types.Text.prototype.toJSON = function () { + return this.value; +}; + +Types.JSON = function JSON(value) { + if (!(this instanceof JSON)) { + return value; + } + this.value = value; +}; // JSON Object +Types.JSON.prototype.toObject = Types.JSON.prototype.toJSON = function () { + return this.value; +}; + +Types.Any = function Any(value) { + if (!(this instanceof Any)) { + return value; + } + this.value = value; +}; // Any Type +Types.Any.prototype.toObject = Types.Any.prototype.toJSON = function () { + return this.value; +}; + +module.exports = function (modelTypes) { - var List = require('./list.js'); var GeoPoint = require('./geo').GeoPoint; - /** - * Schema types - */ - Types.Text = function Text(value) { - if (!(this instanceof Text)) { - return value; - } - this.value = value; - }; // Text type + for(var t in Types) { + modelTypes[t] = Types[t]; + } - Types.Text.prototype.toObject = Types.Text.prototype.toJSON = function () { - return this.value; - }; - - Types.JSON = function JSON(value) { - if (!(this instanceof JSON)) { - return value; - } - this.value = value; - }; // JSON Object - Types.JSON.prototype.toObject = Types.JSON.prototype.toJSON = function () { - return this.value; - }; - - Types.Any = function Any(value) { - if (!(this instanceof Any)) { - return value; - } - this.value = value; - }; // Any Type - Types.Any.prototype.toObject = Types.Any.prototype.toJSON = function () { - return this.value; - }; - - Types.schemaTypes = {}; - Types.registerType = function (type, names) { + modelTypes.schemaTypes = {}; + modelTypes.registerType = function (type, names) { names = names || []; names = names.concat([type.name]); for (var n = 0; n < names.length; n++) { @@ -46,16 +50,18 @@ module.exports = function (Types) { } }; - Types.registerType(Types.Text); - Types.registerType(Types.JSON); - Types.registerType(Types.Any); + modelTypes.registerType(Types.Text); + modelTypes.registerType(Types.JSON); + modelTypes.registerType(Types.Any); - Types.registerType(String); - Types.registerType(Number); - Types.registerType(Boolean); - Types.registerType(Date); - Types.registerType(Buffer, ['Binary']); - Types.registerType(Array); - Types.registerType(GeoPoint); - Types.registerType(Object); -}; \ No newline at end of file + modelTypes.registerType(String); + modelTypes.registerType(Number); + modelTypes.registerType(Boolean); + modelTypes.registerType(Date); + modelTypes.registerType(Buffer, ['Binary']); + modelTypes.registerType(Array); + modelTypes.registerType(GeoPoint); + modelTypes.registerType(Object); +}; + +module.exports.Types = Types; \ No newline at end of file