-
Notifications
You must be signed in to change notification settings - Fork 312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use collectionName for ModelStore key when modelName isn't set #253
base: master
Are you sure you want to change the base?
Changes from 1 commit
d44286e
894572e
78aa90b
c0dccfd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,7 +20,7 @@ function ModelUtils(entryPath) { | |
this._classMap = {}; | ||
} | ||
|
||
ModelUtils.prototype.getModel = function(path, attrs, options, callback) { | ||
ModelUtils.prototype.getModel = function(path, attrs, options, callback, fallbackToBaseModel) { | ||
var Model; | ||
attrs = attrs || {}; | ||
options = options || {}; | ||
|
@@ -29,7 +29,15 @@ ModelUtils.prototype.getModel = function(path, attrs, options, callback) { | |
callback(new Model(attrs, options)); | ||
}); | ||
} else { | ||
Model = this.getModelConstructor(path); | ||
try { | ||
Model = this.getModelConstructor(path) | ||
} catch (e) { | ||
if (e.code === 'MODULE_NOT_FOUND' && fallbackToBaseModel) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, |
||
Model = BaseModel; | ||
} else { | ||
throw e; | ||
} | ||
} | ||
return new Model(attrs, options); | ||
} | ||
}; | ||
|
@@ -87,7 +95,7 @@ ModelUtils.prototype.isCollection = function(obj) { | |
ModelUtils.prototype.getModelNameForCollectionName = function(collectionName) { | ||
var Collection; | ||
Collection = this.getCollectionConstructor(collectionName); | ||
return this.modelName(Collection.prototype.model); | ||
return this.modelOrCollectionName(Collection.prototype.model); | ||
}; | ||
|
||
ModelUtils.uppercaseRe = /([A-Z])/g; | ||
|
@@ -121,7 +129,7 @@ ModelUtils.prototype.underscorize = function(name) { | |
* -> "" | ||
* MyClass.id = "MyClass" | ||
*/ | ||
ModelUtils.prototype.modelName = function(modelOrCollectionClass) { | ||
ModelUtils.prototype.modelOrCollectionName = function(modelOrCollectionClass) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we can find a less verbose name for this? Perhaps we could use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It actually describes exactly what the method does. I think the problem here is not the name but rather doing two things at once. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I absolutely agree that I think that this is just a naming issue, though, and not a problem of trying to do two things in one method. This method takes a constructor and returns its underscorized id. I see that as one task with multiple applications. |
||
return this.underscorize(modelOrCollectionClass.id || modelOrCollectionClass.name); | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,46 +14,52 @@ ModelStore.prototype = Object.create(Super.prototype); | |
ModelStore.prototype.constructor = ModelStore; | ||
|
||
ModelStore.prototype.set = function(model) { | ||
var existingAttrs, id, key, modelName, newAttrs; | ||
var existingAttrs, id, key, modelOrCollectionName, newAttrs, constructor; | ||
|
||
id = model.get(model.idAttribute); | ||
modelName = this.modelUtils.modelName(model.constructor); | ||
if (modelName == null) { | ||
throw new Error('Undefined modelName for model'); | ||
modelOrCollectionName = this.modelUtils.modelOrCollectionName(model.constructor); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this case, it will always be a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, as @shebson said in the PR description:
So this method may return the But you are right this behaviour is very confusing and we should probably try to find a better solution to fix #151. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @spikebrehm is right. On this line, the I agree that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I haven't seen that this is implemented different as in #252. If you rename it to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think |
||
if (!modelOrCollectionName && model.collection) { | ||
modelOrCollectionName = this.modelUtils.modelOrCollectionName(model.collection.constructor); | ||
} | ||
key = this._getModelStoreKey(modelName, id); | ||
/** | ||
* If the model is not named and not part of a named collection, | ||
* fall back to an empty string to preserve existing behavior. | ||
*/ | ||
modelOrCollectionName = modelOrCollectionName || ''; | ||
key = this._getModelStoreKey(modelOrCollectionName, id); | ||
|
||
/** | ||
* We want to merge the model attrs with whatever is already | ||
* present in the store. | ||
*/ | ||
existingAttrs = this.get(modelName, id) || {}; | ||
existingAttrs = this.get(modelOrCollectionName, id) || {}; | ||
newAttrs = _.extend({}, existingAttrs, model.toJSON()); | ||
return Super.prototype.set.call(this, key, newAttrs, null); | ||
}; | ||
|
||
ModelStore.prototype.get = function(modelName, id, returnModelInstance) { | ||
ModelStore.prototype.get = function(modelOrCollectionName, id, returnModelInstance) { | ||
var key, modelData; | ||
|
||
if (returnModelInstance == null) { | ||
returnModelInstance = false; | ||
} | ||
key = this._getModelStoreKey(modelName, id); | ||
key = this._getModelStoreKey(modelOrCollectionName, id); | ||
|
||
modelData = Super.prototype.get.call(this, key); | ||
if (modelData) { | ||
if (returnModelInstance) { | ||
return this.modelUtils.getModel(modelName, modelData, { | ||
return this.modelUtils.getModel(modelOrCollectionName, modelData, { | ||
app: this.app | ||
}); | ||
}, null, true); | ||
} else { | ||
return modelData; | ||
} | ||
} | ||
}; | ||
|
||
ModelStore.prototype.find = function(modelName, params) { | ||
ModelStore.prototype.find = function(modelOrCollectionName, params) { | ||
var prefix, foundCachedObject, _this, data, foundCachedObjectKey; | ||
prefix = this._formatKey(this._keyPrefix(modelName)); | ||
prefix = this._formatKey(this._keyPrefix(modelOrCollectionName)); | ||
_this = this; | ||
// find the cached object that has attributes which are a subset of the params | ||
foundCachedObject = _.find(this.cache, function(cacheObject, key) { | ||
|
@@ -88,10 +94,10 @@ function isObjectSubset(potentialSubset, objectToTest) { | |
}); | ||
} | ||
|
||
ModelStore.prototype._keyPrefix = function(modelName) { | ||
return this.modelUtils.underscorize(modelName); | ||
ModelStore.prototype._keyPrefix = function(modelOrCollectionName) { | ||
return this.modelUtils.underscorize(modelOrCollectionName); | ||
} | ||
|
||
ModelStore.prototype._getModelStoreKey = function(modelName, id) { | ||
return this._keyPrefix(modelName) + ":" + id; | ||
ModelStore.prototype._getModelStoreKey = function(modelOrCollectionName, id) { | ||
return this._keyPrefix(modelOrCollectionName) + ":" + id; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Under what circumstances would
fallbackToBaseModel
betrue
vsfalse
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fallbackToBaseModel
is true inModelStore#get
whenreturnModelInstance
is true. In all other cases, it defaults to false.This option makes
getModel
return an instance ofbaseModel
when the path does not exist. We need this behavior for instances where a collection usesBaseModel
. In that case,ModelStore#get
passes acollectionName
as the path instead of amodelName
.We could make this behavior the default (and remove the
fallbackToBaseModel
parameter) without causing any tests to fail, but I elected to make this behavior optional because I can imagine scenarios in which you would want an exception when passing a non-existent path togetModel
.Another approach would be to leave
getModel
unchanged and handle the exception inModelStore#get
, but that seems like it would lead to needless code repetition.