From 7caaeb26233dbd4a94ac29ee7c4ca14165da1c69 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Fri, 17 May 2013 14:41:04 -0700 Subject: [PATCH] Fix the datasource.define --- examples/datasource-app.js | 86 +++++++++++-- index.js | 2 +- lib/adl.js | 3 - lib/datasource.js | 25 +++- lib/model.js | 4 - lib/railway.js | 250 ------------------------------------- lib/relations.js | 2 +- 7 files changed, 100 insertions(+), 272 deletions(-) delete mode 100644 lib/railway.js diff --git a/examples/datasource-app.js b/examples/datasource-app.js index 96f2520a..1af2ba25 100644 --- a/examples/datasource-app.js +++ b/examples/datasource-app.js @@ -1,21 +1,38 @@ var DataSource = require('../../jugglingdb').DataSource; var ds = new DataSource('memory'); + +var Article = ds.define('Article', {title: String}); +var Tag = ds.define('Tag', {name: String}); +Article.hasAndBelongsToMany('tags'); + +Article.create(function(e, article) { + article.tags.create({name: 'popular'}, function (err, data) { + Article.findOne(function(e, article) { + article.tags(function(e, tags) { + console.log(tags); + }); + }); + }); +}); + // define models var Post = ds.define('Post', { - title: { type: String, length: 255 }, - content: { type: DataSource.Text }, - date: { type: Date, default: function () { return new Date;} }, - timestamp: { type: Number, default: Date.now }, + title: { type: String, length: 255 }, + content: { type: DataSource.Text }, + date: { type: Date, default: function () { + return new Date; + } }, + timestamp: { type: Number, default: Date.now }, published: { type: Boolean, default: false, index: true } }); // simplier way to describe model var User = ds.define('User', { - name: String, - bio: DataSource.Text, - approved: Boolean, - joinedAt: Date, - age: Number + name: String, + bio: DataSource.Text, + approved: Boolean, + joinedAt: Date, + age: Number }); var Group = ds.define('Group', {name: String}); @@ -28,9 +45,54 @@ User.prototype.getNameAndAge = function () { var user = new User({name: 'Joe'}); console.log(user); -console.log(ds.models); -console.log(ds.definitions); - +// console.log(ds.models); +// console.log(ds.definitions); + +// setup relationships +User.hasMany(Post, {as: 'posts', foreignKey: 'userId'}); + +// creates instance methods: +// user.posts(conds) +// user.posts.build(data) // like new Post({userId: user.id}); +// user.posts.create(data) // build and save + +Post.belongsTo(User, {as: 'author', foreignKey: 'userId'}); +// creates instance methods: +// post.author(callback) -- getter when called with function +// post.author() -- sync getter when called without params +// post.author(user) -- setter when called with object + +User.hasAndBelongsToMany('groups'); + +var user2 = new User({name: 'Smith'}); +user2.save(function (err) { + console.log(user2); + var post = user2.posts.build({title: 'Hello world'}); + post.save(function(err, data) { + console.log(err ? err: data); + }); +}); + +Post.findOne({where: {published: false}, order: 'date DESC'}, function (err, data) { + console.log(data); +}); + +User.create({name: 'Jeff'}, function (err, data) { + if (err) { + console.log(err); + return; + } + console.log(data); + var post = data.posts.build({title: 'My Post'}); + console.log(post); +}); + +User.create({name: 'Ray'}, function (err, data) { + console.log(data); +}); + +var count = 5; +setInterval(function() {console.log(count--); if(!count) process.exit(0);}, 100); diff --git a/index.js b/index.js index 9dd7eaa4..c249caee 100644 --- a/index.js +++ b/index.js @@ -2,8 +2,8 @@ var fs = require('fs'); var path = require('path'); exports.ADL = require('./lib/adl').Schema; -exports.Schema = require('./lib/schema').Schema; exports.DataSource = require('./lib/datasource').DataSource; +exports.Schema = exports.DataSource; // require('./lib/schema').Schema; exports.ModelBaseClass = require('./lib/model.js'); var baseSQL = './lib/sql'; diff --git a/lib/adl.js b/lib/adl.js index 619cc29c..1fcb4d8b 100644 --- a/lib/adl.js +++ b/lib/adl.js @@ -225,9 +225,6 @@ function standartize(properties, settings) { Schema.prototype.defineProperty = function (model, prop, params) { this.definitions[model].properties[prop] = params; this.models[model].registerProperty(prop); - if (this.adapter.defineProperty) { - this.adapter.defineProperty(model, prop, params); - } }; /** diff --git a/lib/datasource.js b/lib/datasource.js index 967bc9d3..affcd395 100644 --- a/lib/datasource.js +++ b/lib/datasource.js @@ -60,7 +60,7 @@ util.inherits(DataSource, ADL); // Copy over statics for (var m in ADL) { - if (!DataSource[m]) { + if (!DataSource.hasOwnProperty(m) && 'super_' !== m) { DataSource[m] = ADL[m]; } } @@ -180,6 +180,15 @@ DataSource.prototype.setup = function(name, settings) { * ``` */ DataSource.prototype.define = function defineClass(className, properties, settings) { + var args = slice.call(arguments); + + if (!className) throw new Error('Class name required'); + if (args.length == 1) properties = {}, args.push(properties); + if (args.length == 2) settings = {}, args.push(settings); + + properties = properties || {}; + settings = settings || {}; + var NewClass = ADL.prototype.define.call(this, className, properties, settings); // inherit DataAccessObject methods @@ -203,6 +212,20 @@ DataSource.prototype.define = function defineClass(className, properties, settin }; +/** + * Define single property named `prop` on `model` + * + * @param {String} model - name of model + * @param {String} prop - name of propery + * @param {Object} params - property settings + */ +DataSource.prototype.defineProperty = function (model, prop, params) { + ADL.prototype.defineProperty.call(this, model, prop, params); + + if (this.adapter.defineProperty) { + this.adapter.defineProperty(model, prop, params); + } +}; /** * Drop each model table and re-create. diff --git a/lib/model.js b/lib/model.js index 7e48fa64..fe0b8628 100644 --- a/lib/model.js +++ b/lib/model.js @@ -241,7 +241,3 @@ function isdef(s) { return s !== undef; } -ModelBaseClass.prototype.dataSource = function(name, settings) { - require('./jutil').inherits(this.constructor, require('./dao')); -} - diff --git a/lib/railway.js b/lib/railway.js deleted file mode 100644 index 2d014a81..00000000 --- a/lib/railway.js +++ /dev/null @@ -1,250 +0,0 @@ -var fs = require('fs'); -var path = require('path'); -var Schema = require('./schema').Schema; - -var existsSync = fs.existsSync || path.existsSync; - -if (global.railway) { - railway.orm._schemas = []; -} - -module.exports = function init(root) { - var railway, app, models; - - if (typeof root !== 'object' || (root.constructor.name !== 'Compound' && root.constructor.name !== 'CompoundServer')) { - railway = global.railway; - app = global.app; - models = app.models; - } else { - railway = root; - app = railway.app; - root = railway.root; - models = railway.models; - } - - railway.orm._schemas = []; - - var confFile = (root || app.root) + '/config/database'; - var config = {}; - - try { - var cf = require(confFile); - if (cf instanceof Array) cf = cf[0]; - if (typeof cs === 'function') { - config = cs(railway); - } else { - config = cf[app.set('env')]; - } - } catch (e) { - console.log('Could not load config/database.{js|json|yml}'); - throw e; - } - - // when driver name started with point - look for driver in app root (relative path) - if (config.driver && config.driver.match(/^\./)) { - config.driver = path.join(app.root, config.driver); - } - - var schema = new Schema(config && config.driver || 'memory', config); - schema.log = log; - - if (!schema.adapter) throw new Error('Adapter is not defined'); - - if (schema.waitForConnect) { - schema.on('connected', function() { - loadSchema(schema, railway, app, models); - }); - } else { - loadSchema(schema, railway, app, models); - } - -// check validations and display warning - -var displayWarning = false; -Object.keys(models).forEach(function (model) { - var Model = models[model]; - if (Model._validations) { - displayWarning = true; - } -}); - -if (displayWarning) { - var $ = railway.utils.stylize.$; - // require('util').puts($('WARNING:').bold.red + ' ' + $('I can see that you\'ve added validation to db/schema.js. However schema.js file is only used to describe database schema. Therefore validations configured in db/schema.js will be ignored.\nFor business logic (incl. validations) please create models as separate .js files here: app/models/*.js').yellow); -} - -function loadSchema(schema, railway, app, models) { - railway.orm._schemas.push(schema); - - var context = prepareContext(models, railway, app, schema); - - // run schema first - var schemaFile = (root || app.root) + '/db/schema.'; - if (existsSync(schemaFile + 'js')) { - schemaFile += 'js'; - } else if (existsSync(schemaFile + 'coffee')) { - schemaFile += 'coffee'; - } else { - schemaFile = false; - } - - if (schemaFile) { - var code = fs.readFileSync(schemaFile).toString(); - if (schemaFile.match(/\.coffee$/)) { - code = require('coffee-script').compile(code); - } - var fn = new Function('context', 'require', 'with(context){(function(){' + code + '})()}'); - fn(context, require); - } - - // autoupdate if set app.enable('autoupdate') or freeze schemas by default - railway.orm._schemas.forEach(function (schema) { - if(app.enabled('autoupdate')){ - schema.autoupdate(); - } else { - schema.freeze(); - } - }); -} - -function log(str, startTime) { - var $ = railway.utils.stylize.$; - var m = Date.now() - startTime; - railway.utils.debug(str + $(' [' + (m < 10 ? m : $(m).red) + ' ms]').bold); - app.emit('app-event', { - type: 'query', - param: str, - time: m - }); -} - -function prepareContext(models, railway, app, defSchema, done) { - var ctx = {app: app}, - _models = {}, - settings = {}, - cname, - schema, - connected = 0, - wait = 0, - nonJugglingSchema = false; - - done = done || function () {}; - - /** - * Multiple schemas support - * example: - * schema('redis', {url:'...'}, function () { - * describe models using redis connection - * ... - * }); - * schema(function () { - * describe models stored in memory - * ... - * }); - */ - ctx.schema = function () { - var name = argument('string'); - var opts = argument('object') || {}; - var def = argument('function') || function () {}; - schema = new Schema(name || opts.driver || 'memory', opts); - railway.orm._schemas.push(schema); - wait += 1; - ctx.gotSchema = true; - schema.on('log', log); - schema.on('connected', function () { - if (wait === ++connected) done(); - }); - def(); - schema = false; - }; - - /** - * Use custom schema driver - */ - ctx.customSchema = function () { - var def = argument('function') || function () {}; - nonJugglingSchema = true; - def(); - Object.keys(ctx.exports).forEach(function (m) { - ctx.define(m, ctx.exports[m]); - }); - nonJugglingSchema = false; - }; - ctx.exports = {}; - ctx.module = { exports: ctx.exports }; - - /** - * Define a class in current schema - */ - ctx.describe = ctx.define = function (className, callback) { - var m; - cname = className; - _models[cname] = {}; - settings[cname] = {}; - if (nonJugglingSchema) { - m = callback; - } else { - callback && callback(); - m = (schema || defSchema).define(className, _models[cname], settings[cname]); - } - if (global.railway) { - global[cname] = m; - } - return models[cname] = ctx[cname] = m; - }; - - /** - * Define a property in current class - */ - ctx.property = function (name, type, params) { - if (!params) params = {}; - if (typeof type !== 'function' && typeof type === 'object' && !(type instanceof Array)) { - params = type; - type = String; - } - params.type = type || String; - _models[cname][name] = params; - }; - - /** - * Set custom table name for current class - * @param name - name of table - */ - ctx.setTableName = function (name) { - if (cname) settings[cname].table = name; - }; - - /** - * Set configuration param - * - * @param name - name of param. - * @param value - value. - */ - ctx.set = function (name, value) { - if (cname) settings[cname][name] = value; - }; - - ctx.pathTo = railway.map && railway.map.pathTo || {}; - - /** - * If the Schema has additional types, add them to the context - * e.g. MySQL has an additional Point type - */ - if (Schema.types && Object.keys(Schema.types).length) { - for (var typeName in Schema.types) { - ctx[typeName] = Schema.types[typeName]; - } - } - - return ctx; - - function argument(type) { - var r; - [].forEach.call(arguments.callee.caller.arguments, function (a) { - if (!r && typeof a === type) r = a; - }); - return r; - } -} - -}; diff --git a/lib/relations.js b/lib/relations.js index 8daba2d7..9fd5b162 100644 --- a/lib/relations.js +++ b/lib/relations.js @@ -5,7 +5,7 @@ var i8n = require('inflection'); var defineScope = require('./scope.js').defineScope; /** - * Relations mixins for ./model.js + * Relations mixins for ./dao.js */ var Model = require('./dao.js');