Skip to content
This repository has been archived by the owner on Jul 12, 2018. It is now read-only.

Commit

Permalink
- introduced static Model.initialize-method
Browse files Browse the repository at this point in the history
- models are now bootstrapped more intelligently
  • Loading branch information
jhnns committed Nov 24, 2013
1 parent 0fb55a1 commit 7f6f72f
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 77 deletions.
48 changes: 13 additions & 35 deletions lib/shared/Model.class.js
Expand Up @@ -10,7 +10,6 @@ var value = require("value"),
log = require("./logger.js").get("shared"),
schemaHelpers = require("./helpers/schema.js"),
validate = require("./validator.js").validate,
schemas = require("./registries/schemaRegistry.js"),
services = require("./registries/serviceRegistry.js"),
ModelCollection = require("./ModelCollection.class.js"),
config = require("./config.js"),
Expand Down Expand Up @@ -113,38 +112,22 @@ var Model = EventEmitter.extend("Model", Junction, {
* @param {String|Number} id
*/
constructor: function (id) {
var url = this.url,
localSchema = schemas.getSchema(url),
sharedSchema = schemas.getSchema(url, "shared"),
service;
// Check if the model-class is initialize-able and if it has already been initialized.
// Will only be executed once per model
if (this.Class.initialized !== true && typeof this.Class.initialize === "function") {
this.Class.initialize();
}

this._ids = {};
this._signals = {};
this._url = url;
this._url = this.url;

if (localSchema) {
this.setSchema(localSchema, "local");
// Set the sharedSchema as well, but don't update _keys, _defaults, etc.
this._sharedSchema = sharedSchema || null;
} else if (sharedSchema) {
this.setSchema(sharedSchema);
} else {
this.reset();
}
// Initialize attributes object
this.reset();

if (value(id).isSet()) {
this.setId(id);
}

if (config.use !== undefined && (config.use.casting === undefined || config.use.casting === false)) {
this._casting = true;
}

//load service
service = services.getService(url);
if (service !== null) {
this.setService(service);
}
},

/**
Expand Down Expand Up @@ -274,22 +257,15 @@ var Model = EventEmitter.extend("Model", Junction, {
*/
setSchema: function (schema, schemaType) {

var schemaData;

if (schemaType === "local") {
this._localSchema = schema;
} else {
this._sharedSchema = schema;
}

// Update internal properties only if its a local schema or there is no localSchema defined.
if (schemaType === "local" || !this._localSchema) {
schemaData = schemaHelpers.processSchema(schema);

this._keys = schemaData.keys;
this._defaults = schemaData.defaults;
this._types = schemaData.types;
this._setters = schemaData.setters;
// Update internal properties only if its a local schema or if there is no localSchema defined.
if (schemaType === "local" || this.hasOwnProperty("_localSchema") === false) {
schemaHelpers.applySchema(this, schema);

this.reset();
}
Expand Down Expand Up @@ -910,6 +886,8 @@ Model.extend = function () {
url;

EventEmitter.mixin(Class);
Class.initialized = false;
Class.initialize = modelStatics.initialize;
Class.find = modelStatics.find;
Class.findById = modelStatics.findById;
Class.getResourceUrl = modelStatics.getResourceUrl;
Expand Down
14 changes: 14 additions & 0 deletions lib/shared/helpers/schema.js
Expand Up @@ -172,7 +172,21 @@ function getFields(schema, attr) {

}

/**
* @param {Object} model
* @param {Object} schema
*/
function applySchema(model, schema) {
var schemaData = processSchema(schema);

model._keys = schemaData.keys;
model._defaults = schemaData.defaults;
model._types = schemaData.types;
model._setters = schemaData.setters;
}

exports.processSchema = processSchema;
exports.getReadableFields = getReadableFields;
exports.getWriteableFields = getWriteableFields;
exports.getUnwriteableFieldsForData = getUnwriteableFieldsForData;
exports.applySchema = applySchema;
48 changes: 43 additions & 5 deletions lib/shared/modelStatics.js
@@ -1,14 +1,43 @@
"use strict";

var services = require("./registries/serviceRegistry.js"),
schemas = require("./registries/schemaRegistry.js"),
serviceAdapter = require("./helpers/serviceAdapter.js"),
createModelInstances = require("./helpers/createModelInstances.js"),
env = require("./env.js"),
_getResourceUrl = require("./helpers/getResourceUrl.js"),
Event = require("./Event.class.js"),
emitErrorEvent = require("./helpers/emitErrorEvent.js"),
schemaHelpers = require("./helpers/schema.js"),
config = require("./config.js"),
_ = require("underscore");

/**
* Looks up the model's schemas and services and applies it to the prototype.
* Will be called once per Model-class
*
* @this {Class}
*/
function initialize() { /* jshint validthis: true */
var ModelClass = this,
url = ModelClass.prototype.url,
localSchema = schemas.getSchema(url),
sharedSchema = schemas.getSchema(url, "shared");

if (localSchema) {
schemaHelpers.applySchema(ModelClass.prototype, localSchema);
ModelClass.prototype._localSchema = localSchema;
ModelClass.prototype._sharedSchema = sharedSchema;
} else if (sharedSchema) {
schemaHelpers.applySchema(ModelClass.prototype, sharedSchema);
ModelClass.prototype._sharedSchema = sharedSchema;
}

ModelClass.prototype._service = services.getService(url);
ModelClass.prototype._casting = config.use.casting;
ModelClass.initialized = true;
}

/**
* Find a fully populated model-Instance by given ID
*
Expand All @@ -25,8 +54,9 @@ var services = require("./registries/serviceRegistry.js"),
* @param {String|Object|Function} ids the parent IDs
* @param {String|Number|Function=} id the ID of the model you want to load
* @param {Function} callback
* @this {Class}
*/
function findById(remote, ids, id, callback) {
function findById(remote, ids, id, callback) { /* jshint validthis: true */

var args = Array.prototype.slice.call(arguments, 0),
ModelClass = this,
Expand Down Expand Up @@ -95,13 +125,13 @@ function findById(remote, ids, id, callback) {
* @param {Object|Function} ids the parent ids for embedded-document finds
* @param {Object|Function=} params the params you want to select your models by
* @param {Function=} callback
*
* @this {Class}
*/
function find(remote, ids, params, callback) {
function find(remote, ids, params, callback) { /* jshint validthis: true */

var ModelClass = this,
url = ModelClass.prototype.url,
service = services.getService(url),
service = ModelClass.prototype._service,
args = Array.prototype.slice.call(arguments, 0),
modelInstance;

Expand Down Expand Up @@ -171,7 +201,14 @@ function find(remote, ids, params, callback) {
});
}

function getResourceUrl(ids) {
/**
* Generates a resource url for the given ids.
*
* @param {Object} ids
* @returns {String}
* @this {Function}
*/
function getResourceUrl(ids) { /* jshint validthis: true */
return _getResourceUrl(this.prototype.url, ids);
}

Expand All @@ -190,6 +227,7 @@ var ErrorEvent = Event.extend("ErrorEvent", {
}
});

exports.initialize = initialize;
exports.find = find;
exports.findById = findById;
exports.getResourceUrl = getResourceUrl;
2 changes: 1 addition & 1 deletion lib/shared/registries/schemaRegistry.js
Expand Up @@ -23,7 +23,7 @@ function setSchema(schemaName, schemaDefinition, schemaType) {
/**
* get the schema for the given path
* @param {String} schemaName
* @param {String} type (server/shared/client)
* @param {String=} type (server/shared/client)
* @return {Function}
*/
function getSchema(schemaName, type) {
Expand Down
50 changes: 21 additions & 29 deletions test/client/ModelService.test.js
Expand Up @@ -129,7 +129,7 @@ describe("Model-Services", function () {
describe("#find", function () {

beforeEach(function () {
testService = {
Octocat.prototype._service = testService = {
readCollection : function (remote, ids, params, callback) {
callback({ status : "success", data : mockedOctocats });
}
Expand Down Expand Up @@ -196,7 +196,7 @@ describe("Model-Services", function () {

it("should call the remote-service if no client-service is defined", function (done) {

testService = null;
Octocat.prototype._service = null;

Octocat.find({ da : "ta" }, function (err, models) {
expect(err).to.be(null);
Expand All @@ -207,7 +207,7 @@ describe("Model-Services", function () {

it("should fail if no client-service is defined and remote = false", function (done) {

testService = null;
Octocat.prototype._service = null;

Octocat.find(false, { da : "ta" }, function (err, models) {
expect(err).not.to.be(null);
Expand All @@ -217,11 +217,9 @@ describe("Model-Services", function () {

it("should pass the remote service as 'remote' attribute if called with remote = true", function (done) {

testService = {
readCollection : function (remote, ids, params, callback) {
expect(remote).to.be.a("function");
callback({ status : "success", data : mockedOctocats });
}
testService.readCollection = function (remote, ids, params, callback) {
expect(remote).to.be.a("function");
callback({ status : "success", data : mockedOctocats });
};

Octocat.find(true, { da : "ta" }, function (err, models) {
Expand All @@ -234,11 +232,9 @@ describe("Model-Services", function () {

it("should not pass the remote function if called with remote = false", function (done) {

testService = {
readCollection : function (remote, ids, params, callback) {
expect(remote).to.be(false);
callback({ status : "success", data : mockedOctocats });
}
testService.readCollection = function (remote, ids, params, callback) {
expect(remote).to.be(false);
callback({ status : "success", data : mockedOctocats });
};

Octocat.find(false, { da : "ta" }, function (err, models) {
Expand All @@ -256,7 +252,7 @@ describe("Model-Services", function () {
Octocat.cache = null;
});
beforeEach(function () {
testService = {
Octocat.prototype._service = testService = {
read : function mockedRead(remote, ids, callback) {
var octocat = mockedOctocats[ids.octocat - 1];
callback({ status : "success", data : octocat });
Expand Down Expand Up @@ -339,7 +335,7 @@ describe("Model-Services", function () {

it("should call the remote service if no client service is defined", function (done) {

testService = null;
Octocat.prototype._service = null;

Octocat.findById(1, function (err, model) {
expect(err).to.be(null);
Expand All @@ -350,7 +346,7 @@ describe("Model-Services", function () {

it("should return an error if no service is defined when called with remote = false", function (done) {

testService = null;
Octocat.prototype._service = null;

Octocat.findById(false, 1, function (err, model) {
expect(err).to.be.an(Error);
Expand All @@ -360,19 +356,15 @@ describe("Model-Services", function () {

it("should pass the remote service as 'remote' attribute if called with remote = true", function (done) {

testService = {
read : function (remote, id, callback) {

expect(remote).to.be.a("function");

callback({
status : "success",
data : {
id : 1,
name : "RemoteOcto"
}
});
}
testService.read = function (remote, id, callback) {
expect(remote).to.be.a("function");
callback({
status : "success",
data : {
id : 1,
name : "RemoteOcto"
}
});
};

Octocat.findById(1, function (err, model) {
Expand Down
9 changes: 2 additions & 7 deletions test/shared/ModelService.test.js
Expand Up @@ -439,20 +439,15 @@ function sharedModelServiceTest(env) {
describe("Statics", function () {

var Octocat,
testService,
services;
testService;

before(function () {
Octocat = require("../shared/Model/Octocat.class.js");
services = require("../../lib/shared/registries/serviceRegistry.js");
services.getService = function () {
return testService;
};
});

beforeEach(function () {
Octocat.cache = new ModelCache();
testService = {};
Octocat.prototype._service = testService = {};
});

describe("#find", function () {
Expand Down

0 comments on commit 7f6f72f

Please sign in to comment.