ember-data-factory-guy 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gruntfile.js +1 -0
- data/README.md +45 -26
- data/bower.json +1 -1
- data/dist/ember-data-factory-guy.js +247 -124
- data/dist/ember-data-factory-guy.min.js +1 -1
- data/ember-data-factory-guy.gemspec +1 -1
- data/package.json +2 -7
- data/src/factory_guy.js +56 -24
- data/src/factory_guy_test_mixin.js +26 -7
- data/src/model_definition.js +41 -16
- data/src/sequence.js +2 -3
- data/src/store.js +123 -74
- data/tests/active_model_adapter_factory_test.js +9 -2
- data/tests/factory_guy_test.js +28 -1
- data/tests/fixture_adapter_factory_test.js +15 -15
- data/tests/rest_adapter_factory_test.js +35 -1
- data/vendor/assets/javascripts/ember_data_factory_guy.js +247 -124
- metadata +2 -2
@@ -1 +1 @@
|
|
1
|
-
Sequence=function(fn){var index=1;
|
1
|
+
Sequence=function(fn){var index=1;this.next=function(){return fn.call(this,index++)};this.reset=function(){index=1}};function MissingSequenceError(message){this.toString=function(){return message}}ModelDefinition=function(model,config){var sequences={};var defaultAttributes={};var namedModels={};var modelId=1;this.model=model;this.matchesName=function(name){return model==name||namedModels[name]};this.merge=function(config){};this.generate=function(sequenceName){var sequence=sequences[sequenceName];if(!sequence){throw new MissingSequenceError("Can not find that sequence named ["+sequenceName+"] in '"+model+"' definition")}return sequence.next()};this.build=function(name,opts){var modelAttributes=namedModels[name]||{};var fixture=$.extend({},defaultAttributes,modelAttributes,opts);for(attribute in fixture){if(typeof fixture[attribute]=="function"){fixture[attribute]=fixture[attribute].call(this,fixture)}}if(!fixture.id){fixture.id=modelId++}return fixture};this.buildList=function(name,number,opts){var arr=[];for(var i=0;i<number;i++){arr.push(this.build(name,opts))}return arr};this.reset=function(){modelId=1;for(name in sequences){sequences[name].reset()}};var parseDefault=function(object){if(!object){return}defaultAttributes=object};var parseSequences=function(object){if(!object){return}for(sequenceName in object){var sequenceFn=object[sequenceName];if(typeof sequenceFn!="function"){throw new Error("Problem with ["+sequenceName+"] sequence definition. Sequences must be functions")}object[sequenceName]=new Sequence(sequenceFn)}sequences=object};var parseConfig=function(config){parseSequences(config.sequences);delete config.sequences;parseDefault(config.default);delete config.default;namedModels=config};parseConfig(config)};FactoryGuy={modelDefinitions:{},define:function(model,config){if(this.modelDefinitions[model]){this.modelDefinitions[model].merge(config)}else{this.modelDefinitions[model]=new ModelDefinition(model,config)}},generate:function(sequenceName){return function(){return this.generate(sequenceName)}},lookupModelForName:function(name){for(model in this.modelDefinitions){var definition=this.modelDefinitions[model];if(definition.matchesName(name)){return definition.model}}},lookupDefinitionForName:function(name){for(model in this.modelDefinitions){var definition=this.modelDefinitions[model];if(definition.matchesName(name)){return definition}}},build:function(name,opts){var definition=this.lookupDefinitionForName(name);if(!definition){throw new Error("Can't find that factory named ["+name+"]")}return definition.build(name,opts)},buildList:function(name,number,opts){var definition=this.lookupDefinitionForName(name);if(!definition){throw new Error("Can't find that factory named ["+name+"]")}return definition.buildList(name,number,opts)},resetModels:function(store){var typeMaps=store.typeMaps;for(model in this.modelDefinitions){var definition=this.modelDefinitions[model];definition.reset();try{var modelType=store.modelFor(definition.model);if(store.usingFixtureAdapter()){modelType.FIXTURES=[]}store.unloadAll(modelType)}catch(e){}}},pushFixture:function(modelClass,fixture){if(!modelClass["FIXTURES"]){modelClass["FIXTURES"]=[]}modelClass["FIXTURES"].push(fixture);return fixture},clear:function(opts){if(!opts){this.modelDefinitions={};return}}};DS.Store.reopen({usingFixtureAdapter:function(){var adapter=this.adapterFor("application");return adapter instanceof DS.FixtureAdapter},makeFixture:function(name,options){var modelName=FactoryGuy.lookupModelForName(name);var fixture=FactoryGuy.build(name,options);var modelType=this.modelFor(modelName);if(this.usingFixtureAdapter()){this.setBelongsToFixturesAdapter(modelType,modelName,fixture);return FactoryGuy.pushFixture(modelType,fixture)}else{var self=this;var model;Em.run(function(){model=self.push(modelName,fixture);self.setBelongsToRESTAdapter(modelType,modelName,model)});return model}},makeList:function(name,number,options){var arr=[];for(var i=0;i<number;i++){arr.push(this.makeFixture(name,options))}return arr},setBelongsToFixturesAdapter:function(modelType,modelName,parentFixture){var store=this;var adapter=this.adapterFor("application");var relationShips=Ember.get(modelType,"relationshipNames");if(relationShips.hasMany){relationShips.hasMany.forEach(function(relationship){var hasManyModel=store.modelFor(Em.String.singularize(relationship));if(parentFixture[relationship]){parentFixture[relationship].forEach(function(id){var hasManyfixtures=adapter.fixturesForType(hasManyModel);var fixture=adapter.findFixtureById(hasManyfixtures,id);fixture[modelName]=parentFixture.id})}})}},setBelongsToRESTAdapter:function(modelType,modelName,model){var self=this;Ember.get(modelType,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="hasMany"){var children=model.get(name)||[];children.forEach(function(child){child.set(modelName,model)})}if(relationship.kind=="belongsTo"){var belongsToRecord=model.get(name);if(belongsToRecord){var hasManyName=self.findHasManyRelationshipName(belongsToRecord,model);belongsToRecord.get(hasManyName).addObject(model)}}})},findHasManyRelationshipName:function(belongToModel,childModel){var relationshipName;Ember.get(belongToModel.constructor,"relationshipsByName").forEach(function(name,relationship){if(relationship.kind=="hasMany"&&relationship.type==childModel.constructor){relationshipName=relationship.key}});return relationshipName},pushPayload:function(type,payload){if(this.usingFixtureAdapter()){var model=this.modelFor(modelName);FactoryGuy.pushFixture(model,payload)}else{this._super(type,payload)}}});DS.FixtureAdapter.reopen({createRecord:function(store,type,record){var promise=this._super(store,type,record);promise.then(function(){var relationShips=Ember.get(type,"relationshipNames");if(relationShips.belongsTo){relationShips.belongsTo.forEach(function(relationship){var belongsToRecord=record.get(relationship);if(belongsToRecord){var hasManyName=store.findHasManyRelationshipName(belongsToRecord,record);belongsToRecord.get(hasManyName).addObject(record)}})}});return promise}});FactoryGuyTestMixin=Em.Mixin.create({setup:function(app){this.set("container",app.__container__);return this},useFixtureAdapter:function(app){app.ApplicationAdapter=DS.FixtureAdapter;this.getStore().adapterFor("application").simulateRemoteResponse=false},find:function(type,id){return this.getStore().find(type,id)},make:function(name,opts){return this.getStore().makeFixture(name,opts)},getStore:function(){return this.get("container").lookup("store:main")},pushPayload:function(type,hash){return this.getStore().pushPayload(type,hash)},pushRecord:function(type,hash){return this.getStore().push(type,hash)},stubEndpointForHttpRequest:function(url,json,options){options=options||{};var request={url:url,dataType:"json",responseText:json,type:options.type||"GET",status:options.status||200};if(options.data){request.data=options.data}$.mockjax(request)},handleCreate:function(name,opts){var model=FactoryGuy.lookupModelForName(name);this.stubEndpointForHttpRequest("/"+Em.String.pluralize(model),this.buildAjaxCreateResponse(name,opts),{type:"POST"})},buildAjaxCreateResponse:function(name,opts){var fixture=FactoryGuy.build(name,opts);var model=FactoryGuy.lookupModelForName(name);var hash={};hash[model]=fixture;return hash},handleUpdate:function(root,id){this.stubEndpointForHttpRequest("/"+Em.String.pluralize(root)+"/"+id,{},{type:"PUT"})},handleDelete:function(root,id){this.stubEndpointForHttpRequest("/"+Em.String.pluralize(root)+"/"+id,{},{type:"DELETE"})},teardown:function(){FactoryGuy.resetModels(this.getStore())}});
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
Gem::Specification.new do |s|
|
3
3
|
s.name = "ember-data-factory-guy"
|
4
|
-
s.version = "0.
|
4
|
+
s.version = "0.2.0"
|
5
5
|
s.platform = Gem::Platform::RUBY
|
6
6
|
s.authors = ["Daniel Sudol", "Alex Opak"]
|
7
7
|
s.email = ["dansudol@yahoo.com", "opak.alexandr@gmail.com"]
|
data/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "ember-data-factory-guy",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.2.0",
|
4
4
|
"authors": [
|
5
5
|
"Daniel Sudol <dansudol@yahoo.com>",
|
6
6
|
"Opak Alex <opak.alexandr@gmail.com>"
|
@@ -14,28 +14,23 @@
|
|
14
14
|
"FixtureAdapter"
|
15
15
|
],
|
16
16
|
"license": "MIT",
|
17
|
-
|
18
17
|
"bugs": {
|
19
18
|
"url": ""
|
20
19
|
},
|
21
|
-
|
22
20
|
"scripts": {
|
23
21
|
"test": "grunt test"
|
24
22
|
},
|
25
|
-
|
26
23
|
"repository": {
|
27
24
|
"type": "git",
|
28
25
|
"url": ""
|
29
26
|
},
|
30
|
-
|
31
27
|
"devDependencies": [
|
32
28
|
"grunt-contrib-coffee",
|
33
29
|
"grunt-contrib-concat",
|
34
30
|
"grunt-contrib-uglify",
|
35
31
|
"grunt-contrib-qunit"
|
36
32
|
],
|
37
|
-
|
38
33
|
"engines": {
|
39
34
|
"node": ">=v0.10.1"
|
40
35
|
}
|
41
|
-
}
|
36
|
+
}
|
data/src/factory_guy.js
CHANGED
@@ -29,12 +29,12 @@ FactoryGuy = {
|
|
29
29
|
|
30
30
|
```
|
31
31
|
|
32
|
-
For the Person model, you can define fixtures like 'dude' or
|
33
|
-
and get default values.
|
32
|
+
For the Person model, you can define named fixtures like 'dude' or
|
33
|
+
just use 'person' and get default values.
|
34
34
|
|
35
35
|
And to get those fixtures you would call them this way:
|
36
36
|
|
37
|
-
FactoryGuy.build('
|
37
|
+
FactoryGuy.build('dude') or FactoryGuy.build('person')
|
38
38
|
|
39
39
|
@param model the model to define
|
40
40
|
@param config your model definition object
|
@@ -47,18 +47,41 @@ FactoryGuy = {
|
|
47
47
|
}
|
48
48
|
},
|
49
49
|
|
50
|
+
/**
|
51
|
+
Used in model definitions to declare use of a sequence. For example:
|
52
|
+
|
53
|
+
```
|
54
|
+
|
55
|
+
FactoryGuy.define('person', {
|
56
|
+
sequences: {
|
57
|
+
personName: function(num) {
|
58
|
+
return 'person #' + num;
|
59
|
+
}
|
60
|
+
},
|
61
|
+
default: {
|
62
|
+
name: FactoryGuy.generate('personName')
|
63
|
+
}
|
64
|
+
});
|
65
|
+
|
66
|
+
```
|
67
|
+
|
68
|
+
@param {String} sequenceName
|
69
|
+
@returns {Function} wrapper function that is called by the model
|
70
|
+
definition containing the sequence
|
71
|
+
*/
|
50
72
|
generate: function (sequenceName) {
|
51
73
|
return function () {
|
52
74
|
return this.generate(sequenceName);
|
53
75
|
}
|
54
76
|
},
|
55
77
|
|
56
|
-
|
57
78
|
/**
|
79
|
+
Given a name like 'person' or 'dude' determine what model this name
|
80
|
+
refers to. In this case it's 'person' for each one.
|
58
81
|
|
59
|
-
@param name fixture name could be model name like '
|
60
|
-
|
61
|
-
@returns model associated with fixture name
|
82
|
+
@param {String} name a fixture name could be model name like 'person'
|
83
|
+
or a named person in model definition like 'dude'
|
84
|
+
@returns {String} model name associated with fixture name
|
62
85
|
*/
|
63
86
|
lookupModelForName: function (name) {
|
64
87
|
for (model in this.modelDefinitions) {
|
@@ -71,9 +94,9 @@ FactoryGuy = {
|
|
71
94
|
|
72
95
|
/**
|
73
96
|
|
74
|
-
@param name fixture name could be model name like '
|
75
|
-
|
76
|
-
@returns definition associated with model
|
97
|
+
@param {String} name a fixture name could be model name like 'person'
|
98
|
+
or a named person in model definition like 'dude'
|
99
|
+
@returns {ModelDefinition} definition associated with model
|
77
100
|
*/
|
78
101
|
lookupDefinitionForName: function (name) {
|
79
102
|
for (model in this.modelDefinitions) {
|
@@ -91,9 +114,9 @@ FactoryGuy = {
|
|
91
114
|
FactoryGuy.build('user') for User model
|
92
115
|
FactoryGuy.build('bob') for User model with bob attributes
|
93
116
|
|
94
|
-
@param name fixture name
|
95
|
-
@param opts options that will override default fixture values
|
96
|
-
@returns {
|
117
|
+
@param {String} name fixture name
|
118
|
+
@param {Object} opts options that will override default fixture values
|
119
|
+
@returns {Object} json fixture
|
97
120
|
*/
|
98
121
|
build: function (name, opts) {
|
99
122
|
var definition = this.lookupDefinitionForName(name);
|
@@ -109,10 +132,10 @@ FactoryGuy = {
|
|
109
132
|
FactoryGuy.buildList('user', 2) for 2 User models
|
110
133
|
FactoryGuy.build('bob', 2) for 2 User model with bob attributes
|
111
134
|
|
112
|
-
@param name fixture name
|
113
|
-
@param number number of fixtures to create
|
114
|
-
@param opts options that will override default fixture values
|
115
|
-
@returns list of fixtures
|
135
|
+
@param {String} name fixture name
|
136
|
+
@param {Number} number number of fixtures to create
|
137
|
+
@param {Object} opts options that will override default fixture values
|
138
|
+
@returns {Array} list of fixtures
|
116
139
|
*/
|
117
140
|
buildList: function (name, number, opts) {
|
118
141
|
var definition = this.lookupDefinitionForName(name);
|
@@ -123,9 +146,11 @@ FactoryGuy = {
|
|
123
146
|
},
|
124
147
|
|
125
148
|
/**
|
149
|
+
TODO: This is kind of problematic right now .. needs work
|
150
|
+
|
126
151
|
Clear model instances from FIXTURES array, and from store cache.
|
127
152
|
Reset the id sequence for the models back to zero.
|
128
|
-
|
153
|
+
*/
|
129
154
|
resetModels: function (store) {
|
130
155
|
var typeMaps = store.typeMaps;
|
131
156
|
for (model in this.modelDefinitions) {
|
@@ -144,9 +169,6 @@ FactoryGuy = {
|
|
144
169
|
// store.unloadAll(typeMaps[model].type);
|
145
170
|
// }
|
146
171
|
// }
|
147
|
-
|
148
|
-
// for (model in this.modelDefinitions) {
|
149
|
-
// this.modelDefinitions[model].reset();
|
150
172
|
}
|
151
173
|
},
|
152
174
|
|
@@ -154,9 +176,9 @@ FactoryGuy = {
|
|
154
176
|
Push fixture to model's FIXTURES array.
|
155
177
|
Used when store's adapter is a DS.FixtureAdapter.
|
156
178
|
|
157
|
-
@param
|
158
|
-
@param fixture the fixture to add
|
159
|
-
@returns json fixture data
|
179
|
+
@param {DS.Model} modelClass
|
180
|
+
@param {Object} fixture the fixture to add
|
181
|
+
@returns {Object} json fixture data
|
160
182
|
*/
|
161
183
|
pushFixture: function (modelClass, fixture) {
|
162
184
|
if (!modelClass['FIXTURES']) {
|
@@ -164,5 +186,15 @@ FactoryGuy = {
|
|
164
186
|
}
|
165
187
|
modelClass['FIXTURES'].push(fixture);
|
166
188
|
return fixture;
|
189
|
+
},
|
190
|
+
|
191
|
+
/**
|
192
|
+
Clears all model definitions
|
193
|
+
*/
|
194
|
+
clear: function (opts) {
|
195
|
+
if (!opts) {
|
196
|
+
this.modelDefinitions = {};
|
197
|
+
return;
|
198
|
+
}
|
167
199
|
}
|
168
200
|
}
|
@@ -11,6 +11,13 @@ FactoryGuyTestMixin = Em.Mixin.create({
|
|
11
11
|
this.getStore().adapterFor('application').simulateRemoteResponse = false;
|
12
12
|
},
|
13
13
|
|
14
|
+
/**
|
15
|
+
Proxy to store's find method
|
16
|
+
|
17
|
+
@param {String or subclass of DS.Model} type
|
18
|
+
@param {Object|String|Integer|null} id
|
19
|
+
@return {Promise} promise
|
20
|
+
*/
|
14
21
|
find: function(type, id) {
|
15
22
|
return this.getStore().find(type, id);
|
16
23
|
},
|
@@ -31,6 +38,13 @@ FactoryGuyTestMixin = Em.Mixin.create({
|
|
31
38
|
return this.getStore().push(type, hash);
|
32
39
|
},
|
33
40
|
|
41
|
+
/**
|
42
|
+
Using mockjax to stub an http request.
|
43
|
+
|
44
|
+
@param {String} url request url
|
45
|
+
@param {Object} json response
|
46
|
+
@param {Object} options ajax request options
|
47
|
+
*/
|
34
48
|
stubEndpointForHttpRequest: function (url, json, options) {
|
35
49
|
options = options || {};
|
36
50
|
var request = {
|
@@ -49,21 +63,27 @@ FactoryGuyTestMixin = Em.Mixin.create({
|
|
49
63
|
},
|
50
64
|
|
51
65
|
/**
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
66
|
+
Handling ajax POST ( create record ) for a model
|
67
|
+
|
68
|
+
@param {String} name of the fixture ( or model ) to create
|
69
|
+
@param {Object} opts fixture options
|
56
70
|
*/
|
57
71
|
handleCreate: function (name, opts) {
|
58
72
|
var model = FactoryGuy.lookupModelForName(name);
|
59
73
|
this.stubEndpointForHttpRequest(
|
60
74
|
"/" + Em.String.pluralize(model),
|
61
|
-
this.
|
75
|
+
this.buildAjaxCreateResponse(name, opts),
|
62
76
|
{type: 'POST'}
|
63
77
|
)
|
64
78
|
},
|
65
79
|
|
66
|
-
|
80
|
+
/**
|
81
|
+
Build the json used for creating record
|
82
|
+
|
83
|
+
@param {String} name of the fixture ( or model ) to create
|
84
|
+
@param {Object} opts fixture options
|
85
|
+
¬ */
|
86
|
+
buildAjaxCreateResponse: function (name, opts) {
|
67
87
|
var fixture = FactoryGuy.build(name, opts);
|
68
88
|
var model = FactoryGuy.lookupModelForName(name);
|
69
89
|
var hash = {};
|
@@ -86,5 +106,4 @@ FactoryGuyTestMixin = Em.Mixin.create({
|
|
86
106
|
teardown: function () {
|
87
107
|
FactoryGuy.resetModels(this.getStore());
|
88
108
|
}
|
89
|
-
|
90
109
|
})
|
data/src/model_definition.js
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
/**
|
2
|
+
A ModelDefinition encapsulates a model's definition
|
3
|
+
|
4
|
+
@param model
|
5
|
+
@param config
|
6
|
+
@constructor
|
7
|
+
*/
|
1
8
|
ModelDefinition = function (model, config) {
|
2
9
|
var sequences = {};
|
3
10
|
var defaultAttributes = {};
|
@@ -6,36 +13,50 @@ ModelDefinition = function (model, config) {
|
|
6
13
|
this.model = model;
|
7
14
|
|
8
15
|
/**
|
9
|
-
@param name model name like 'user' or named type like 'admin'
|
10
|
-
@
|
11
|
-
|
16
|
+
@param {String} name model name like 'user' or named type like 'admin'
|
17
|
+
@returns {Boolean} true if name is this definitions model or this definition
|
18
|
+
contains a named model with that name
|
12
19
|
*/
|
13
20
|
this.matchesName = function (name) {
|
14
21
|
return model == name || namedModels[name];
|
15
22
|
}
|
16
23
|
|
24
|
+
// TODO
|
17
25
|
this.merge = function (config) {
|
18
26
|
}
|
19
27
|
|
20
28
|
/**
|
21
|
-
|
22
|
-
|
29
|
+
Call the next method on the named sequence function
|
30
|
+
|
31
|
+
@param {String} sequenceName
|
32
|
+
@returns {String} output of sequence function
|
23
33
|
*/
|
24
34
|
this.generate = function (sequenceName) {
|
25
|
-
|
26
|
-
|
35
|
+
var sequence = sequences[sequenceName];
|
36
|
+
if (!sequence) {
|
37
|
+
throw new MissingSequenceError("Can not find that sequence named [" + sequenceName + "] in '" + model + "' definition")
|
27
38
|
}
|
28
|
-
return
|
39
|
+
return sequence.next();
|
29
40
|
}
|
30
41
|
|
42
|
+
/**
|
43
|
+
Build a fixture by name
|
44
|
+
|
45
|
+
@param {String} name fixture name
|
46
|
+
@param {Object} opts attributes to override
|
47
|
+
@returns {Object} json
|
48
|
+
*/
|
31
49
|
this.build = function (name, opts) {
|
32
50
|
var modelAttributes = namedModels[name] || {};
|
51
|
+
// merge default, modelAttributes and opts to get the rough fixture
|
33
52
|
var fixture = $.extend({}, defaultAttributes, modelAttributes, opts);
|
34
|
-
|
35
|
-
|
36
|
-
|
53
|
+
// convert attributes that are functions to strings
|
54
|
+
for (attribute in fixture) {
|
55
|
+
if (typeof fixture[attribute] == 'function') {
|
56
|
+
fixture[attribute] = fixture[attribute].call(this, fixture);
|
37
57
|
}
|
38
58
|
}
|
59
|
+
// set the id, unless it was already set in opts
|
39
60
|
if (!fixture.id) {
|
40
61
|
fixture.id = modelId++;
|
41
62
|
}
|
@@ -43,12 +64,12 @@ ModelDefinition = function (model, config) {
|
|
43
64
|
}
|
44
65
|
|
45
66
|
/**
|
46
|
-
|
67
|
+
Build a list of fixtures
|
47
68
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
69
|
+
@param name model name or named model type
|
70
|
+
@param number of fixtures to build
|
71
|
+
@param opts attribute options
|
72
|
+
@returns array of fixtures
|
52
73
|
*/
|
53
74
|
this.buildList = function (name, number, opts) {
|
54
75
|
var arr = [];
|
@@ -58,8 +79,12 @@ ModelDefinition = function (model, config) {
|
|
58
79
|
return arr;
|
59
80
|
}
|
60
81
|
|
82
|
+
// Set the modelId back to 1, and reset the sequences
|
61
83
|
this.reset = function () {
|
62
84
|
modelId = 1;
|
85
|
+
for (name in sequences) {
|
86
|
+
sequences[name].reset();
|
87
|
+
}
|
63
88
|
}
|
64
89
|
|
65
90
|
var parseDefault = function (object) {
|
data/src/sequence.js
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
Sequence = function (fn) {
|
2
2
|
var index = 1;
|
3
|
-
var fn = fn;
|
4
3
|
|
5
4
|
this.next = function () {
|
6
5
|
return fn.call(this, index++);
|
@@ -9,8 +8,8 @@ Sequence = function (fn) {
|
|
9
8
|
this.reset = function () {
|
10
9
|
index = 1;
|
11
10
|
}
|
12
|
-
}
|
11
|
+
};
|
13
12
|
|
14
13
|
function MissingSequenceError(message) {
|
15
14
|
this.toString = function() { return message }
|
16
|
-
}
|
15
|
+
};
|
data/src/store.js
CHANGED
@@ -1,17 +1,19 @@
|
|
1
1
|
DS.Store.reopen({
|
2
|
-
|
3
|
-
|
2
|
+
/**
|
3
|
+
@returns {Boolean} true if store's adapter is DS.FixtureAdapter
|
4
|
+
*/
|
5
|
+
usingFixtureAdapter: function () {
|
4
6
|
var adapter = this.adapterFor('application');
|
5
|
-
return adapter instanceof DS.FixtureAdapter
|
7
|
+
return adapter instanceof DS.FixtureAdapter;
|
6
8
|
},
|
7
9
|
|
8
10
|
/**
|
9
|
-
|
10
|
-
|
11
|
+
Make new fixture and save to store. If the store is using FixtureAdapter,
|
12
|
+
will push to FIXTURE array, otherwise will use push method on adapter.
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
@param {String} name name of fixture
|
15
|
+
@param {Object} options fixture options
|
16
|
+
@returns {Object|DS.Model} json or record depending on the adapter type
|
15
17
|
*/
|
16
18
|
makeFixture: function (name, options) {
|
17
19
|
var modelName = FactoryGuy.lookupModelForName(name);
|
@@ -24,7 +26,7 @@ DS.Store.reopen({
|
|
24
26
|
} else {
|
25
27
|
var self = this;
|
26
28
|
var model;
|
27
|
-
Em.run(
|
29
|
+
Em.run(function () {
|
28
30
|
model = self.push(modelName, fixture);
|
29
31
|
self.setBelongsToRESTAdapter(modelType, modelName, model);
|
30
32
|
});
|
@@ -33,13 +35,13 @@ DS.Store.reopen({
|
|
33
35
|
},
|
34
36
|
|
35
37
|
/**
|
36
|
-
|
38
|
+
Make a list of Fixtures
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
@param {String} name name of fixture
|
41
|
+
@param {Number} number number to create
|
42
|
+
@param {Object} options fixture options
|
43
|
+
@returns {Array} list of json fixtures or records depending on the adapter type
|
44
|
+
*/
|
43
45
|
makeList: function (name, number, options) {
|
44
46
|
var arr = [];
|
45
47
|
for (var i = 0; i < number; i++) {
|
@@ -49,16 +51,16 @@ DS.Store.reopen({
|
|
49
51
|
},
|
50
52
|
|
51
53
|
/**
|
52
|
-
|
53
|
-
|
54
|
+
Set the belongsTo association for FixtureAdapter,
|
55
|
+
with models that have a hasMany association.
|
54
56
|
|
55
|
-
|
56
|
-
|
57
|
-
|
57
|
+
For example if a user hasMany projects, then set the user.id
|
58
|
+
on each project that the user hasMany of, so that the project
|
59
|
+
now has the belongsTo user association setup.
|
58
60
|
|
59
|
-
|
60
|
-
|
61
|
-
|
61
|
+
@param {String} modelType model type like App.User
|
62
|
+
@param {String} modelName model name like 'user'
|
63
|
+
@param {Object} parentFixture parent to assign as belongTo
|
62
64
|
*/
|
63
65
|
setBelongsToFixturesAdapter: function (modelType, modelName, parentFixture) {
|
64
66
|
var store = this;
|
@@ -68,7 +70,7 @@ DS.Store.reopen({
|
|
68
70
|
relationShips.hasMany.forEach(function (relationship) {
|
69
71
|
var hasManyModel = store.modelFor(Em.String.singularize(relationship));
|
70
72
|
if (parentFixture[relationship]) {
|
71
|
-
parentFixture[relationship].forEach(function(id) {
|
73
|
+
parentFixture[relationship].forEach(function (id) {
|
72
74
|
var hasManyfixtures = adapter.fixturesForType(hasManyModel);
|
73
75
|
var fixture = adapter.findFixtureById(hasManyfixtures, id);
|
74
76
|
fixture[modelName] = parentFixture.id;
|
@@ -79,38 +81,59 @@ DS.Store.reopen({
|
|
79
81
|
},
|
80
82
|
|
81
83
|
/**
|
82
|
-
|
83
|
-
with a hasMany association
|
84
|
+
For the REST type models:
|
84
85
|
|
85
|
-
|
86
|
-
on each project that the user hasMany of, so that the project
|
87
|
-
now has the belongsTo user association setup
|
86
|
+
Set the belongsTo association with a hasMany association
|
88
87
|
|
89
|
-
|
90
|
-
|
91
|
-
|
88
|
+
Set this model in the parent hasMany array this model belongsTo
|
89
|
+
|
90
|
+
For example if a user hasMany projects, then set the user
|
91
|
+
on each project that the user hasMany of, so that the project
|
92
|
+
now has the belongsTo user association setup
|
93
|
+
|
94
|
+
@param {DS.Model} modelType model type like 'User'
|
95
|
+
@param {String} modelName model name like 'user'
|
96
|
+
@param {DS.Model} model
|
92
97
|
*/
|
93
|
-
setBelongsToRESTAdapter: function (modelType, modelName,
|
94
|
-
var
|
98
|
+
setBelongsToRESTAdapter: function (modelType, modelName, model) {
|
99
|
+
var self = this;
|
100
|
+
Ember.get(modelType, 'relationshipsByName').forEach(function (name, relationship) {
|
101
|
+
if (relationship.kind == 'hasMany') {
|
102
|
+
var children = model.get(name) || [];
|
103
|
+
children.forEach(function (child) {
|
104
|
+
child.set(modelName, model)
|
105
|
+
})
|
106
|
+
}
|
107
|
+
|
108
|
+
if (relationship.kind == 'belongsTo') {
|
109
|
+
var belongsToRecord = model.get(name);
|
110
|
+
if (belongsToRecord) {
|
111
|
+
var hasManyName = self.findHasManyRelationshipName(belongsToRecord, model)
|
112
|
+
belongsToRecord.get(hasManyName).addObject(model);
|
113
|
+
}
|
114
|
+
}
|
115
|
+
})
|
116
|
+
},
|
95
117
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
118
|
+
findHasManyRelationshipName: function (belongToModel, childModel) {
|
119
|
+
var relationshipName;
|
120
|
+
Ember.get(belongToModel.constructor, 'relationshipsByName').forEach(
|
121
|
+
function (name, relationship) {
|
122
|
+
if (relationship.kind == 'hasMany' &&
|
123
|
+
relationship.type == childModel.constructor) {
|
124
|
+
relationshipName = relationship.key;
|
103
125
|
}
|
104
|
-
}
|
105
|
-
|
126
|
+
}
|
127
|
+
)
|
128
|
+
return relationshipName;
|
106
129
|
},
|
107
130
|
|
108
131
|
/**
|
109
|
-
|
110
|
-
|
132
|
+
Adding a pushPayload for FixtureAdapter, but using the original with
|
133
|
+
other adapters that support pushPayload.
|
111
134
|
|
112
|
-
|
113
|
-
|
135
|
+
@param {String} type
|
136
|
+
@param {Object} payload
|
114
137
|
*/
|
115
138
|
pushPayload: function (type, payload) {
|
116
139
|
if (this.usingFixtureAdapter()) {
|
@@ -126,34 +149,60 @@ DS.Store.reopen({
|
|
126
149
|
DS.FixtureAdapter.reopen({
|
127
150
|
|
128
151
|
/**
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
152
|
+
Overriding createRecord to add the record created to the
|
153
|
+
hashMany records for all of the records that this record belongsTo.
|
154
|
+
|
155
|
+
For example:
|
156
|
+
|
157
|
+
If models are defined like so:
|
158
|
+
|
159
|
+
User = DS.Model.extend({
|
160
|
+
projects: DS.hasMany('project')
|
161
|
+
})
|
162
|
+
|
163
|
+
Project = DS.Model.extend({
|
164
|
+
user: DS.belongsTo('user')
|
165
|
+
})
|
166
|
+
|
167
|
+
and you create a project record with a user defined:
|
168
|
+
store.createRecord('project', {user: user})
|
169
|
+
|
170
|
+
this method will take the new project created and add it to the user's 'projects'
|
171
|
+
hasMany array.
|
172
|
+
|
173
|
+
And a full code example:
|
174
|
+
|
175
|
+
var userJson = store.makeFixture('user');
|
176
|
+
|
177
|
+
store.find('user', userJson.id).then(function(user) {
|
178
|
+
store.createRecord('project', {user: user}).save()
|
179
|
+
.then( function(project) {
|
180
|
+
// user.get('projects.length') == 1;
|
181
|
+
})
|
182
|
+
})
|
183
|
+
|
184
|
+
@method createRecord
|
185
|
+
@param {DS.Store} store
|
186
|
+
@param {subclass of DS.Model} type
|
187
|
+
@param {DS.Model} record
|
188
|
+
@return {Promise} promise
|
189
|
+
*/
|
190
|
+
createRecord: function (store, type, record) {
|
140
191
|
var promise = this._super(store, type, record);
|
141
192
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
193
|
+
promise.then(function () {
|
194
|
+
var relationShips = Ember.get(type, 'relationshipNames');
|
195
|
+
if (relationShips.belongsTo) {
|
196
|
+
relationShips.belongsTo.forEach(function (relationship) {
|
197
|
+
var belongsToRecord = record.get(relationship);
|
198
|
+
if (belongsToRecord) {
|
199
|
+
var hasManyName = store.findHasManyRelationshipName(belongsToRecord, record);
|
200
|
+
belongsToRecord.get(hasManyName).addObject(record);
|
201
|
+
}
|
202
|
+
})
|
203
|
+
}
|
204
|
+
});
|
205
|
+
|
155
206
|
return promise;
|
156
207
|
}
|
157
|
-
|
158
|
-
})
|
159
|
-
|
208
|
+
})
|