ember-data-factory-guy 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
})
|