From 227c2d05cdcbd5b0970a87bcf67126190e135dad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= <miroslav@strongloop.com>
Date: Sun, 25 May 2014 16:27:45 +0200
Subject: [PATCH] app: flatten model config

Support flat structure of model config objects, where model options
are set as top-level properties.

Before:

    Customer: {
      dataSource: 'db',
      options: {
        base: 'User'
      }
    }

Now:

    Customer: {
      dataSource: 'db',
      base: 'User'
    }
---
 lib/application.js | 26 +++++++++++++++++++++++++-
 test/app.test.js   | 33 +++++++++++++++++++++++++++++----
 2 files changed, 54 insertions(+), 5 deletions(-)

diff --git a/lib/application.js b/lib/application.js
index 6e71ce7c..3ceed368 100644
--- a/lib/application.js
+++ b/lib/application.js
@@ -7,6 +7,7 @@ var DataSource = require('loopback-datasource-juggler').DataSource
   , compat = require('./compat')
   , assert = require('assert')
   , fs = require('fs')
+  , extend = require('util')._extend
   , _ = require('underscore')
   , RemoteObjects = require('strong-remoting')
   , swagger = require('strong-remoting/ext/swagger')
@@ -540,7 +541,10 @@ function dataSourcesFromConfig(config) {
 }
 
 function modelFromConfig(name, config, app) {
-  var ModelCtor = require('./loopback').createModel(name, config.properties, config.options);
+  var options = buildModelOptionsFromConfig(config);
+  var properties = config.properties;
+
+  var ModelCtor = require('./loopback').createModel(name, properties, options);
   var dataSource = config.dataSource;
 
   if(typeof dataSource === 'string') {
@@ -553,6 +557,26 @@ function modelFromConfig(name, config, app) {
   return ModelCtor;
 }
 
+function buildModelOptionsFromConfig(config) {
+  var options = extend({}, config.options);
+  for (var key in config) {
+    if (['properties', 'options', 'dataSource'].indexOf(key) !== -1) {
+      // Skip items which have special meaning
+      continue;
+    }
+
+    if (options[key] !== undefined) {
+      // When both `config.key` and `config.options.key` are set,
+      // use the latter one to preserve backwards compatibility
+      // with loopback 1.x
+      continue;
+    }
+
+    options[key] = config[key];
+  }
+  return options;
+}
+
 function requireDir(dir, basenames) {
   assert(dir, 'cannot require directory contents without directory name');
 
diff --git a/test/app.test.js b/test/app.test.js
index 47f31795..2dcdb918 100644
--- a/test/app.test.js
+++ b/test/app.test.js
@@ -61,9 +61,11 @@ describe('app', function() {
     });
   });
 
-  describe('app.model(name, properties, options)', function () {
-    it('Sugar for defining a fully built model', function () {
-      var app = loopback();
+  describe('app.model(name, config)', function () {
+    var app;
+
+    beforeEach(function() {
+      app = loopback();
       app.boot({
         app: {port: 3000, host: '127.0.0.1'},
         dataSources: {
@@ -72,16 +74,39 @@ describe('app', function() {
           }
         }
       });
+    });
 
+    it('Sugar for defining a fully built model', function () {
       app.model('foo', {
         dataSource: 'db'
       });
 
       var Foo = app.models.foo;
-      var f = new Foo;
+      var f = new Foo();
 
       assert(f instanceof loopback.Model);
     });
+
+    it('interprets extra first-level keys as options', function() {
+      app.model('foo', {
+        dataSource: 'db',
+        base: 'User'
+      });
+
+      expect(app.models.foo.definition.settings.base).to.equal('User');
+    });
+
+    it('prefers config.options.key over config.key', function() {
+      app.model('foo', {
+        dataSource: 'db',
+        base: 'User',
+        options: {
+          base: 'Application'
+        }
+      });
+
+      expect(app.models.foo.definition.settings.base).to.equal('Application');
+    });
   });
 
   describe('app.models', function() {