kojac 0.9.1 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +6 -14
- data/.gitignore +4 -0
- data/Gemfile +1 -1
- data/app/assets/javascripts/kojac.js +393 -125
- data/app/assets/javascripts/kojac_canjs.js +34 -34
- data/app/assets/javascripts/kojac_ember.js +110 -152
- data/app/controllers/{kojac_controller.rb → kojac_base_controller.rb} +18 -11
- data/app/policies/kojac_base_policy.rb +114 -0
- data/app/serializers/kojac_base_serializer.rb +35 -0
- data/kojac.gemspec +12 -10
- data/lib/kojac/app_serialize.rb +31 -29
- data/lib/kojac/concentric.rb +152 -0
- data/lib/kojac/kojac_policy.rb +70 -0
- data/lib/kojac/kojac_rails.rb +200 -49
- data/lib/kojac/version.rb +1 -1
- data/spec/can_cache_spec.js +19 -19
- data/spec/demo/.gitignore +16 -0
- data/spec/demo/.ruby-gemset +1 -0
- data/spec/demo/.ruby-version +1 -0
- data/spec/demo/Gemfile +59 -0
- data/spec/demo/Gemfile.lock +153 -0
- data/spec/demo/README.rdoc +15 -248
- data/spec/demo/Rakefile +25 -1
- data/spec/demo/app/{mailers/.gitkeep → assets/images/.keep} +0 -0
- data/spec/demo/app/assets/javascripts/application.js +3 -3
- data/spec/demo/app/controllers/application_controller.rb +6 -1
- data/spec/demo/app/{models/.gitkeep → controllers/concerns/.keep} +0 -0
- data/spec/demo/app/controllers/users_controller.rb +5 -0
- data/spec/demo/{lib/assets/.gitkeep → app/mailers/.keep} +0 -0
- data/spec/demo/{log/.gitkeep → app/models/.keep} +0 -0
- data/spec/demo/app/models/concerns/.keep +0 -0
- data/spec/demo/app/models/user.rb +36 -0
- data/spec/demo/app/policies/user_policy.rb +42 -0
- data/spec/demo/bin/bundle +3 -0
- data/spec/demo/bin/rails +4 -0
- data/spec/demo/bin/rake +4 -0
- data/spec/demo/config.ru +1 -1
- data/spec/demo/config/application.rb +14 -46
- data/spec/demo/config/application.yml +4 -0
- data/spec/demo/config/boot.rb +3 -9
- data/spec/demo/config/database.yml +6 -6
- data/spec/demo/config/environment.rb +4 -2
- data/spec/demo/config/environments/development.rb +11 -19
- data/spec/demo/config/environments/production.rb +40 -27
- data/spec/demo/config/environments/test.rb +13 -14
- data/spec/demo/config/initializers/concentric_config.rb +9 -0
- data/spec/demo/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/demo/config/initializers/inflections.rb +6 -5
- data/spec/demo/config/initializers/initialize_kojac.rb +16 -0
- data/spec/demo/config/initializers/secret_token.rb +7 -2
- data/spec/demo/config/initializers/session_store.rb +0 -5
- data/spec/demo/config/initializers/wrap_parameters.rb +6 -6
- data/spec/demo/config/locales/en.yml +20 -2
- data/spec/demo/config/routes.rb +24 -24
- data/spec/demo/db/migrate/20131212034312_add_user.rb +14 -0
- data/spec/demo/db/migrate/20140107085351_add_owner_id.rb +5 -0
- data/spec/demo/db/schema.rb +28 -0
- data/spec/demo/db/seeds.rb +7 -0
- data/spec/demo/lib/assets/.keep +0 -0
- data/spec/demo/lib/tasks/.keep +0 -0
- data/spec/demo/log/.keep +0 -0
- data/spec/demo/public/404.html +43 -11
- data/spec/demo/public/422.html +43 -11
- data/spec/demo/public/500.html +43 -11
- data/spec/demo/public/robots.txt +5 -0
- data/spec/demo/spec/controllers/allowed_fields_spec.rb +171 -0
- data/spec/demo/spec/factories/users.rb +9 -0
- data/spec/demo/spec/features/concentric_spec.rb +63 -0
- data/spec/demo/spec/features/serialization_spec.rb +86 -0
- data/spec/demo/spec/spec_helper.rb +133 -0
- data/spec/demo/spec/spec_utils.rb +42 -0
- data/spec/demo/vendor/assets/javascripts/.keep +0 -0
- data/spec/demo/vendor/assets/stylesheets/.keep +0 -0
- data/spec/ember_factory_spec.js +1 -1
- data/spec/ember_model_spec.js +13 -3
- data/spec/ember_tojsono_spec.js +105 -0
- data/spec/error_handling_spec.js +90 -0
- data/spec/external/underscore_plus.js +318 -9
- data/spec/kojac_caching_spec.js +3 -1
- data/spec/kojac_ember_cache_spec.js +9 -0
- data/spec/kojac_mock_spec.js +4 -4
- data/spec/kojac_operations_spec.js +4 -4
- data/spec/local_provider_spec.js +184 -0
- data/spec/model_ring_spec.rb +2 -2
- data/spec/operation_include_spec.js +2 -2
- data/spec/run.html +34 -24
- data/spec/type_conversion_spec.js +38 -0
- data/vendor/assets/javascripts/jstorage.js +950 -0
- metadata +115 -129
- data/Gemfile.lock +0 -157
- data/app/serializers/default_kojac_serializer.rb +0 -10
- data/lib/kojac/ring_strong_parameters.rb +0 -195
- data/spec/.DS_Store +0 -0
- data/spec/demo/script/rails +0 -6
- data/spec/external/.DS_Store +0 -0
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
MzljZTFhZmZiNzdkYjE1YWJmMzg5M2M5ZjQ3NTI3NmQxYzhiZThkMjYwMDgw
|
10
|
-
MzdmZTNiZmU0NTFkMTEyNWRjNDRiN2ZmYjA3MGYyN2Q3ZmVkZmFhMjYzYzhm
|
11
|
-
NDk0YmU3YmUzZGQwYzllZTBmZjUyYjNmNGVkYmMyMTAyNzViZDg=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
ODE2MDU0YWJjMzVhMzY4M2EwNGY5YjMxODFiZTE0YWQ5N2FhZDJkY2UxZTUy
|
14
|
-
MGE0Mzk0MTk0OTRkNGNkYTVmNjcxMGExZGY1ZDg1YzYwYzk2MmUwNTExZjZi
|
15
|
-
MjBiODcyZTc1OWQ1MGQxNzAwNjk0OGExZDk2NThhMTM0NGM3MDI=
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b718cc81d1c3dedf9f6a4e92a627a92214a0d118
|
4
|
+
data.tar.gz: aec9fe24896b2965108f802c435861f5b7db5f0e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0bfff9ecf7789c0ad74e4aaf4d90062e8a565d2800199080e7d11daef67b9f0882eff16ddad1d54aef3da9ccfb0af1aa6c75379a6d1dd7d456a95b8db704bc2f
|
7
|
+
data.tar.gz: a8c65fb7708a6eddd730fecbf58984c87528fbca403260a0ca895340058868794f5850755282cd0ec7824b270f55e2926cf70f7f80a1546f38853b8c9124e91d
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -6,7 +6,7 @@ source "https://rubygems.org"
|
|
6
6
|
gemspec
|
7
7
|
|
8
8
|
# jquery-rails is used by the dummy application
|
9
|
-
gem "jquery-rails"
|
9
|
+
#gem "jquery-rails"
|
10
10
|
|
11
11
|
# Declare any dependencies that are still in development here instead of in
|
12
12
|
# your gemspec. These might include edge Rails or gems from your path or
|
@@ -159,16 +159,81 @@ Kojac.Utils = {
|
|
159
159
|
return _.flatten(_.pairs(aKeyValues),true); // this style : {key1: value, key2: value}
|
160
160
|
} else
|
161
161
|
return null; // unrecognised input
|
162
|
-
}
|
162
|
+
},
|
163
|
+
|
164
|
+
// pass a copy aPropListFn aCopyFn when you have a complex object eg. ember class. It will not be passed on to recursive calls
|
165
|
+
toJsono: function(aValue,aOptions,aPropListFn,aCopyFn) {
|
166
|
+
if (_.isObjectStrict(aValue)) {
|
167
|
+
if (!aPropListFn && !aCopyFn && ("toJsono" in aValue))
|
168
|
+
aValue = aValue.toJsono(aOptions || {});
|
169
|
+
else {
|
170
|
+
var aDest = {};
|
171
|
+
aOptions = _.clone(aOptions);
|
172
|
+
var aProperties = aPropListFn ? aPropListFn(aValue) : aValue; // may return an array of properties, or an object to use the keys from
|
173
|
+
var aInclude = (aOptions && _.removeKey(aOptions,'include')); // must be an array
|
174
|
+
if (_.isString(aInclude))
|
175
|
+
aInclude = aInclude.split(',');
|
176
|
+
if (aInclude && aInclude.length) {
|
177
|
+
if (_.isArray(aProperties)) //ensure aProperties is an array to add includes
|
178
|
+
aProperties = _.clone(aProperties);
|
179
|
+
else
|
180
|
+
aProperties = _.keys(aProperties);
|
181
|
+
for (var i=0;i<aInclude.length;i++)
|
182
|
+
aProperties.push(aInclude[i]);
|
183
|
+
}
|
184
|
+
var aExclude = (aOptions && _.removeKey(aOptions,'exclude')); // must be an array
|
185
|
+
if (_.isString(aExclude))
|
186
|
+
aExclude = aExclude.split(',');
|
187
|
+
var p;
|
188
|
+
var v;
|
189
|
+
if (_.isArray(aProperties)) {
|
190
|
+
for (var i=0;i<aProperties.length;i++) {
|
191
|
+
p = aProperties[i];
|
192
|
+
if (aExclude && (aExclude.indexOf(p)>=0))
|
193
|
+
continue;
|
194
|
+
if (aCopyFn)
|
195
|
+
aCopyFn(aDest,aValue,p,aOptions);
|
196
|
+
else {
|
197
|
+
aDest[p] = Kojac.Utils.toJsono(aValue[p],aOptions);
|
198
|
+
}
|
199
|
+
}
|
200
|
+
} else { // properties is an object to use keys from
|
201
|
+
for (p in aProperties) {
|
202
|
+
if (aExclude && (aExclude.indexOf(p)>=0))
|
203
|
+
continue;
|
204
|
+
if (aCopyFn)
|
205
|
+
aCopyFn(aDest,aValue,p,aOptions);
|
206
|
+
else {
|
207
|
+
aDest[p] = Kojac.Utils.toJsono(aValue[p],aOptions);
|
208
|
+
}
|
209
|
+
}
|
210
|
+
}
|
211
|
+
aValue = aDest;
|
212
|
+
}
|
213
|
+
} else if (_.isArray(aValue)) {
|
214
|
+
var result = [];
|
215
|
+
for (var i=0; i<aValue.length; i++)
|
216
|
+
result.push(Kojac.Utils.toJsono(aValue[i],aOptions));
|
217
|
+
aValue = result;
|
218
|
+
} else if (_.isDate(aValue)) {
|
219
|
+
aValue = Kojac.interpretValueAsType(aValue,String);
|
220
|
+
}
|
221
|
+
return aValue;
|
222
|
+
},
|
223
|
+
|
224
|
+
// returns an id above the normal 32 bit range of rails but within the range of Javascript
|
225
|
+
createId: function () {
|
226
|
+
return _.randomIntRange(4294967296,4503599627370496); // 2**32 to 2**52 see http://stackoverflow.com/questions/9389315/cross-browser-javascript-number-precision
|
227
|
+
},
|
228
|
+
|
229
|
+
timestamp: function() {
|
230
|
+
return new Date().getTime();
|
231
|
+
},
|
163
232
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
// if (!parts.length)
|
169
|
-
// return 0;
|
170
|
-
// return StringUtils.toInt(parts[parts.length-1])
|
171
|
-
//}
|
233
|
+
resolvedPromise: function() {
|
234
|
+
var d = jQuery.Deferred();
|
235
|
+
return d.resolve.apply(d,arguments);
|
236
|
+
}
|
172
237
|
};
|
173
238
|
|
174
239
|
/*
|
@@ -200,6 +265,9 @@ Kojac.getPropertyValueType = function(aValue) {
|
|
200
265
|
case 'object':
|
201
266
|
result = Object;
|
202
267
|
break;
|
268
|
+
case 'date':
|
269
|
+
result = Date;
|
270
|
+
break;
|
203
271
|
case 'function':
|
204
272
|
case 'class':
|
205
273
|
case 'instance':
|
@@ -233,6 +301,8 @@ Kojac.interpretValueAsType = function(aValue, aDestType) {
|
|
233
301
|
case Boolean:
|
234
302
|
return aValue.toString();
|
235
303
|
break;
|
304
|
+
case Date:
|
305
|
+
return moment(aValue).toISOString();
|
236
306
|
default:
|
237
307
|
case Null:
|
238
308
|
return null;
|
@@ -241,21 +311,7 @@ Kojac.interpretValueAsType = function(aValue, aDestType) {
|
|
241
311
|
|
242
312
|
break;
|
243
313
|
case Boolean:
|
244
|
-
|
245
|
-
switch(sourceType) {
|
246
|
-
case Null:
|
247
|
-
default:
|
248
|
-
return null;
|
249
|
-
break;
|
250
|
-
case Int:
|
251
|
-
case Number:
|
252
|
-
if (isNaN(aValue))
|
253
|
-
return null;
|
254
|
-
else
|
255
|
-
return !!aValue;
|
256
|
-
break;
|
257
|
-
}
|
258
|
-
|
314
|
+
return _.toBoolean(aValue,null);
|
259
315
|
break;
|
260
316
|
|
261
317
|
case Number:
|
@@ -298,6 +354,20 @@ Kojac.interpretValueAsType = function(aValue, aDestType) {
|
|
298
354
|
break;
|
299
355
|
}
|
300
356
|
|
357
|
+
break;
|
358
|
+
case Date:
|
359
|
+
switch(sourceType) {
|
360
|
+
case String:
|
361
|
+
return moment.utc(aValue).toDate();
|
362
|
+
break;
|
363
|
+
case Number:
|
364
|
+
return new Date(aValue);
|
365
|
+
break;
|
366
|
+
case Null:
|
367
|
+
default:
|
368
|
+
return null;
|
369
|
+
break;
|
370
|
+
}
|
301
371
|
break;
|
302
372
|
case Object:
|
303
373
|
return null;
|
@@ -432,7 +502,7 @@ Kojac.Model = Kojac.Object.extend({
|
|
432
502
|
if (['__defaults','__attributes'].indexOf(p)>=0)
|
433
503
|
continue;
|
434
504
|
var propValue = prop[p];
|
435
|
-
if (_.isArray(propValue) && propValue.length===2 && Kojac.FieldTypes.indexOf(propValue[0])>=0) { // in form property: [Type, Default Value]
|
505
|
+
if (_.isArray(propValue) && (propValue.length===2) && (Kojac.FieldTypes.indexOf(propValue[0])>=0)) { // in form property: [Type, Default Value]
|
436
506
|
this.__attributes[p] = propValue[0];
|
437
507
|
prop[p] = propValue[1];
|
438
508
|
} else if (Kojac.FieldTypes.indexOf(propValue) >= 0) { // field type
|
@@ -659,7 +729,7 @@ Kojac.Operation = Kojac.Object.extend({
|
|
659
729
|
verb: null,
|
660
730
|
key: null,
|
661
731
|
value: undefined,
|
662
|
-
results:
|
732
|
+
results: null,
|
663
733
|
result_key: null,
|
664
734
|
result: undefined,
|
665
735
|
error: null, // set with some truthy error if this operation fails
|
@@ -682,6 +752,8 @@ Kojac.Operation = Kojac.Object.extend({
|
|
682
752
|
result = results[response_key];
|
683
753
|
|
684
754
|
results = _.omit(results,response_key); // results now excludes primary result
|
755
|
+
if (!this.results)
|
756
|
+
this.results = {};
|
685
757
|
_.extend(this.results,results); // store other results
|
686
758
|
this.result_key = final_result_key;
|
687
759
|
this.results[final_result_key] = result; // store primary result
|
@@ -700,8 +772,8 @@ Kojac.Request = Kojac.Object.extend({
|
|
700
772
|
ops: [],
|
701
773
|
handlers: null,
|
702
774
|
op: null,
|
703
|
-
result: undefined,
|
704
|
-
results:
|
775
|
+
//result: undefined,
|
776
|
+
//results: null,
|
705
777
|
error: null, // set with some truthy value if this whole request or any operation fails (will contain first error if multiple)
|
706
778
|
newOperation: function() {
|
707
779
|
var obj = new Kojac.Operation({request: this});
|
@@ -720,9 +792,9 @@ Kojac.Request = Kojac.Object.extend({
|
|
720
792
|
// Can give existing keys with id, and will create a clone in database with a new id
|
721
793
|
create: function(aKeyValues,aOptions) {
|
722
794
|
|
723
|
-
var result_key = aOptions && _.removeKey(aOptions,'result_key');
|
724
|
-
var params = aOptions && _.removeKey(aOptions,'params'); // extract specific params
|
725
|
-
var options =
|
795
|
+
var result_key = (aOptions && _.removeKey(aOptions,'result_key'));
|
796
|
+
var params = (aOptions && _.removeKey(aOptions,'params')); // extract specific params
|
797
|
+
var options = _.extend({cacheResults: true, manufacture: true},aOptions || {});
|
726
798
|
|
727
799
|
var kvArray = Kojac.Utils.toKeyValueArray(aKeyValues);
|
728
800
|
for (var i=0;i<kvArray.length-1;i+=2) {
|
@@ -731,7 +803,7 @@ Kojac.Request = Kojac.Object.extend({
|
|
731
803
|
var op = this.newOperation();
|
732
804
|
op.verb = 'CREATE';
|
733
805
|
op.options = _.clone(options);
|
734
|
-
op.params = params && _.clone(params);
|
806
|
+
op.params = (params && _.clone(params));
|
735
807
|
var parts = keySplit(k);
|
736
808
|
if (parts.length >= 3)
|
737
809
|
op.key = k;
|
@@ -748,14 +820,14 @@ Kojac.Request = Kojac.Object.extend({
|
|
748
820
|
// known options will be moved from aOptions to op.options; remaining keys will be put into params
|
749
821
|
read: function(aKeys,aOptions) {
|
750
822
|
var keys = Kojac.Utils.interpretKeys(aKeys);
|
751
|
-
var result_key = aOptions && _.removeKey(aOptions,'result_key'); // extract result_key
|
752
|
-
var params = aOptions && _.removeKey(aOptions,'params'); // extract specific params
|
753
|
-
var options =
|
823
|
+
var result_key = (aOptions && _.removeKey(aOptions,'result_key')); // extract result_key
|
824
|
+
var params = (aOptions && _.removeKey(aOptions,'params')); // extract specific params
|
825
|
+
var options = _.extend({cacheResults: true, manufacture: true},aOptions || {});
|
754
826
|
var me = this;
|
755
827
|
jQuery.each(keys,function(i,k) {
|
756
828
|
var op = me.newOperation();
|
757
829
|
op.options = _.clone(options);
|
758
|
-
op.params = params && _.clone(params);
|
830
|
+
op.params = (params && _.clone(params));
|
759
831
|
op.verb = 'READ';
|
760
832
|
op.key = k;
|
761
833
|
if (i===0)
|
@@ -772,9 +844,9 @@ Kojac.Request = Kojac.Object.extend({
|
|
772
844
|
},
|
773
845
|
|
774
846
|
update: function(aKeyValues,aOptions) {
|
775
|
-
var result_key = aOptions && _.removeKey(aOptions,'result_key');
|
776
|
-
var options =
|
777
|
-
var params = aOptions && _.removeKey(aOptions,'params'); // extract specific params
|
847
|
+
var result_key = (aOptions && _.removeKey(aOptions,'result_key'));
|
848
|
+
var options = _.extend({cacheResults: true, manufacture: true},aOptions || {});
|
849
|
+
var params = (aOptions && _.removeKey(aOptions,'params')); // extract specific params
|
778
850
|
var first=true;
|
779
851
|
var kvArray = Kojac.Utils.toKeyValueArray(aKeyValues);
|
780
852
|
for (var i=0;i<kvArray.length-1;i+=2) {
|
@@ -783,7 +855,7 @@ Kojac.Request = Kojac.Object.extend({
|
|
783
855
|
var op = this.newOperation();
|
784
856
|
op.verb = 'UPDATE';
|
785
857
|
op.options = _.clone(options);
|
786
|
-
op.params = params && _.clone(params);
|
858
|
+
op.params = (params && _.clone(params));
|
787
859
|
op.key = k;
|
788
860
|
if (first) {
|
789
861
|
op.result_key = result_key || k;
|
@@ -797,14 +869,14 @@ Kojac.Request = Kojac.Object.extend({
|
|
797
869
|
|
798
870
|
destroy: function(aKeys,aOptions) {
|
799
871
|
var keys = Kojac.Utils.interpretKeys(aKeys);
|
800
|
-
var result_key = aOptions && _.removeKey(aOptions,'result_key');
|
801
|
-
var options =
|
802
|
-
var params = aOptions && _.removeKey(aOptions,'params'); // extract specific params
|
872
|
+
var result_key = (aOptions && _.removeKey(aOptions,'result_key'));
|
873
|
+
var options = _.extend({cacheResults: true},aOptions || {});
|
874
|
+
var params = (aOptions && _.removeKey(aOptions,'params')); // extract specific params
|
803
875
|
var me = this;
|
804
876
|
jQuery.each(keys,function(i,k) {
|
805
877
|
var op = me.newOperation();
|
806
878
|
op.options = _.clone(options);
|
807
|
-
op.params = params && _.clone(params);
|
879
|
+
op.params = (params && _.clone(params));
|
808
880
|
op.verb = 'DESTROY';
|
809
881
|
op.key = k;
|
810
882
|
if (i===0)
|
@@ -819,10 +891,10 @@ Kojac.Request = Kojac.Object.extend({
|
|
819
891
|
var op = this.newOperation();
|
820
892
|
op.verb = 'EXECUTE';
|
821
893
|
|
822
|
-
var params = aOptions && _.removeKey(aOptions,'params'); // extract specific params
|
823
|
-
op.result_key = aOptions && _.removeKey(aOptions,'result_key') || aKey;
|
824
|
-
op.options =
|
825
|
-
op.params = params && _.clone(params);
|
894
|
+
var params = (aOptions && _.removeKey(aOptions,'params')); // extract specific params
|
895
|
+
op.result_key = (aOptions && _.removeKey(aOptions,'result_key')) || aKey;
|
896
|
+
op.options = _.extend({cacheResults: false, manufacture: false},aOptions || {});
|
897
|
+
op.params = (params && _.clone(params));
|
826
898
|
op.key = aKey;
|
827
899
|
op.value = aValue;
|
828
900
|
return this;
|
@@ -849,53 +921,85 @@ Kojac.Core = Kojac.Object.extend({
|
|
849
921
|
return new Kojac.Request({kojac: this});
|
850
922
|
},
|
851
923
|
|
852
|
-
|
924
|
+
// var v;
|
925
|
+
// for (var i=0;i<aRequest.ops.length;i++) {
|
926
|
+
// var op = aRequest.ops[i];
|
927
|
+
// if (op.error)
|
928
|
+
// break;
|
929
|
+
// if (op.options.cacheResults===false)
|
930
|
+
// continue;
|
931
|
+
// for (p in op.results) {
|
932
|
+
// if (p==op.result_key)
|
933
|
+
// continue;
|
934
|
+
// v = op.results[p];
|
935
|
+
// if (v===undefined)
|
936
|
+
// delete this.cache[p];
|
937
|
+
// else
|
938
|
+
// this.cache[p] = op.results[p];
|
939
|
+
// }
|
940
|
+
// v = op.results[op.result_key];
|
941
|
+
// if (v===undefined) {
|
942
|
+
// delete this.cache[op.result_key];
|
943
|
+
// } else {
|
944
|
+
// this.cache[op.result_key] = v;
|
945
|
+
// }
|
946
|
+
// console.log('end of loop');
|
947
|
+
// }
|
948
|
+
|
949
|
+
handleResults: function(aRequest) {
|
853
950
|
if (this.cache.beginPropertyChanges)
|
854
951
|
this.cache.beginPropertyChanges();
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
952
|
+
|
953
|
+
var updatedObjects = [];
|
954
|
+
|
955
|
+
try {
|
956
|
+
for (var i=0;i<aRequest.ops.length;i++) {
|
957
|
+
var op = aRequest.ops[i];
|
958
|
+
if (op.error)
|
959
|
+
break;
|
960
|
+
|
961
|
+
for (var key in op.results) {
|
962
|
+
var value = op.results[key];
|
963
|
+
if ((op.options.atomise!==false) && _.isObjectStrict(value)) {
|
964
|
+
var existing = this.cache.retrieve(key);
|
965
|
+
if (_.isObjectStrict(existing)) {
|
966
|
+
if (existing.beginPropertyChanges) {
|
967
|
+
existing.beginPropertyChanges();
|
968
|
+
updatedObjects.push(existing);
|
969
|
+
}
|
970
|
+
if (existing.setProperties)
|
971
|
+
existing.setProperties(value);
|
972
|
+
else
|
973
|
+
_.copyProperties(existing,value);
|
974
|
+
value = existing;
|
975
|
+
} else {
|
976
|
+
if ((op.options.manufacture!==false) && (this.objectFactory))
|
977
|
+
value = this.objectFactory.manufacture(value,key);
|
978
|
+
}
|
979
|
+
}
|
980
|
+
op.results[key] = value;
|
981
|
+
if (op.options.cacheResults!==false)
|
982
|
+
this.cache.store(key,value);
|
983
|
+
}
|
868
984
|
}
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
this.cache[op.result_key] = op.results[op.result_key];
|
985
|
+
} finally {
|
986
|
+
for (var i=0;i<updatedObjects.length;i++)
|
987
|
+
updatedObjects[i].endPropertyChanges();
|
873
988
|
}
|
874
989
|
if (this.cache.endPropertyChanges)
|
875
990
|
this.cache.endPropertyChanges();
|
876
991
|
},
|
877
992
|
|
878
|
-
|
879
|
-
var me = this;
|
880
|
-
return _.all(aKeysArray,function(k){
|
881
|
-
return k in me.cache;
|
882
|
-
})
|
883
|
-
},
|
884
|
-
|
885
|
-
cacheValues: function(aKeysArray) {
|
886
|
-
var me = this;
|
887
|
-
return _.map(aKeysArray,function(k){
|
888
|
-
return me.cache[k];
|
889
|
-
})
|
890
|
-
},
|
891
|
-
|
892
|
-
finaliseRequest: function(aRequest) {
|
993
|
+
finaliseResponse: function(aRequest) {
|
893
994
|
// set convenience properties
|
894
995
|
var results = {};
|
895
|
-
for (var i=0;i<aRequest.ops.length;i++) {
|
996
|
+
if (!aRequest.error) for (var i=0;i<aRequest.ops.length;i++) {
|
896
997
|
var op = aRequest.ops[i];
|
897
|
-
if (op.error
|
898
|
-
aRequest.error
|
998
|
+
if (op.error) {
|
999
|
+
if (!aRequest.error)
|
1000
|
+
aRequest.error = op.error;
|
1001
|
+
break;
|
1002
|
+
}
|
899
1003
|
_.extend(results,op.results);
|
900
1004
|
op.result = !op.error && op.results && (op.result_key || op.key) ? op.results[op.result_key || op.key] : null;
|
901
1005
|
if (i===0) {
|
@@ -917,22 +1021,29 @@ Kojac.Core = Kojac.Object.extend({
|
|
917
1021
|
}
|
918
1022
|
}
|
919
1023
|
}
|
920
|
-
aRequest.
|
921
|
-
|
1024
|
+
if (aRequest.error) {
|
1025
|
+
_.removeKey(aRequest,'results');
|
1026
|
+
_.removeKey(aRequest,'result');
|
1027
|
+
} else {
|
1028
|
+
aRequest.results = results;
|
1029
|
+
aRequest.result = (aRequest.op && aRequest.op.result);
|
1030
|
+
}
|
922
1031
|
},
|
923
1032
|
|
924
1033
|
performRequest: function(aRequest) {
|
925
1034
|
for (var i=0;i<aRequest.ops.length;i++) {
|
926
|
-
var op = aRequest.ops[i]
|
1035
|
+
var op = aRequest.ops[i]
|
1036
|
+
op.results = {};
|
927
1037
|
var k = (op.result_key && (op.result_key !== op.key)) ? op.result_key : op.key;
|
928
|
-
|
929
|
-
|
1038
|
+
var cacheValue = aRequest.kojac.cache.retrieve(k);
|
1039
|
+
if ((op.verb=='READ') && op.options.preferCache && (cacheValue!==undefined)) { // resolve from cache
|
1040
|
+
op.results[k] = cacheValue;
|
930
1041
|
var dep_keys = aRequest.kojac.dependentKeys[op.key];
|
931
1042
|
if (dep_keys) {
|
932
1043
|
for (var i=0;i<dep_keys.length;i++) {
|
933
1044
|
var dk = dep_keys[i];
|
934
1045
|
// what if not in cache? perhaps dump siblings in dependentKeys and index key to cause full refresh? or refuse to remove from cache if in dependentKeys
|
935
|
-
op.results[dk] = aRequest.kojac.cache
|
1046
|
+
op.results[dk] = aRequest.kojac.cache.retrieve(dk);
|
936
1047
|
}
|
937
1048
|
}
|
938
1049
|
op.result_key = k;
|
@@ -940,14 +1051,12 @@ Kojac.Core = Kojac.Object.extend({
|
|
940
1051
|
op.performed = true;
|
941
1052
|
}
|
942
1053
|
}
|
943
|
-
aRequest.handlers.add(this.remoteProvider.
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
aRequest.handlers.add(this.cacheResults,null,this);
|
950
|
-
aRequest.handlers.run(aRequest).then(this.finaliseRequest);
|
1054
|
+
aRequest.handlers.add(this.remoteProvider.handleRequest,null,this.remoteProvider);
|
1055
|
+
|
1056
|
+
//if (this.objectFactory)
|
1057
|
+
aRequest.handlers.add(this.handleResults,null,this);
|
1058
|
+
|
1059
|
+
aRequest.handlers.run(aRequest).always(this.finaliseResponse);
|
951
1060
|
return aRequest;
|
952
1061
|
},
|
953
1062
|
|
@@ -1007,6 +1116,21 @@ Kojac.Core = Kojac.Object.extend({
|
|
1007
1116
|
// END Convenience Functions
|
1008
1117
|
});
|
1009
1118
|
|
1119
|
+
Kojac.Cache = Kojac.Object.extend({
|
1120
|
+
store: function(k,v) {
|
1121
|
+
if (v===undefined) {
|
1122
|
+
delete this[k];
|
1123
|
+
return v;
|
1124
|
+
} else {
|
1125
|
+
return (this[k] = v);
|
1126
|
+
}
|
1127
|
+
},
|
1128
|
+
retrieve: function(k) {
|
1129
|
+
return this[k];
|
1130
|
+
}
|
1131
|
+
});
|
1132
|
+
|
1133
|
+
|
1010
1134
|
/**
|
1011
1135
|
* A default RemoteProvider implementation. Your own implementation, or a subclass of this may be used instead.
|
1012
1136
|
* @class Kojac.RemoteProvider
|
@@ -1018,6 +1142,7 @@ Kojac.RemoteProvider = Kojac.Object.extend({
|
|
1018
1142
|
mockFilePath: null,
|
1019
1143
|
mockReadOperationHandler: null,
|
1020
1144
|
serverPath: null,
|
1145
|
+
timeout: 10000,
|
1021
1146
|
|
1022
1147
|
mockWriteOperationHandler: null,//function(aOp) {
|
1023
1148
|
// Ember.Logger.log(JSON.stringify(CanUtils.copyProperties({},aOp,null,['request'])));
|
@@ -1032,12 +1157,9 @@ Kojac.RemoteProvider = Kojac.Object.extend({
|
|
1032
1157
|
key: op.key
|
1033
1158
|
};
|
1034
1159
|
if ((op.verb==='CREATE') || (op.verb==='UPDATE') || (op.verb==='EXECUTE')) {
|
1035
|
-
|
1036
|
-
jsonOp.value = op.value.toObject(op.options);
|
1037
|
-
else
|
1038
|
-
jsonOp.value = op.value;
|
1160
|
+
jsonOp.value = Kojac.Utils.toJsono(op.value,op.options);
|
1039
1161
|
}
|
1040
|
-
var options = op.options && _.omit(op.options,['cacheResults','preferCache']);
|
1162
|
+
var options = (op.options && _.omit(op.options,['cacheResults','preferCache']));
|
1041
1163
|
if (options && !_.isEmpty(options))
|
1042
1164
|
jsonOp.options = options; // omit local keys
|
1043
1165
|
jsonOp.params = op.params;
|
@@ -1046,9 +1168,10 @@ Kojac.RemoteProvider = Kojac.Object.extend({
|
|
1046
1168
|
return result
|
1047
1169
|
},
|
1048
1170
|
|
1049
|
-
|
1171
|
+
handleRequest: function(aRequest) {
|
1050
1172
|
var result;
|
1051
1173
|
var op;
|
1174
|
+
var me = this;
|
1052
1175
|
for (var i=0;i<aRequest.ops.length;i++) {
|
1053
1176
|
op = aRequest.ops[i];
|
1054
1177
|
if (op.performed)
|
@@ -1076,16 +1199,15 @@ Kojac.RemoteProvider = Kojac.Object.extend({
|
|
1076
1199
|
return;
|
1077
1200
|
if (this.useMockFileValues) {
|
1078
1201
|
aRequest.handlers.waitForCallNext = true;
|
1079
|
-
var me = this;
|
1080
1202
|
var getMockFile = function(aOp) {
|
1081
1203
|
var fp = me.mockFilePath+aOp.key+'.js';
|
1082
1204
|
var data = null;
|
1083
|
-
return jQuery.ajax({url: fp, dataType: 'json', cache: false, data: data}).done(
|
1205
|
+
return jQuery.ajax({url: fp, dataType: 'json', cache: false, data: data, timeout: me.timeout}).done(
|
1084
1206
|
function( aData ) {
|
1085
1207
|
for (p in aData) {
|
1086
1208
|
if (p==='results') {
|
1087
1209
|
for (k in aData.results) {
|
1088
|
-
if (k===aOp.key && (aOp.result_key!=aOp.key))
|
1210
|
+
if ((k===aOp.key) && (aOp.result_key!=aOp.key))
|
1089
1211
|
aOp.results[aOp.result_key] = aData.results[k];
|
1090
1212
|
else
|
1091
1213
|
aOp.results[k] = aData.results[k];
|
@@ -1119,6 +1241,7 @@ Kojac.RemoteProvider = Kojac.Object.extend({
|
|
1119
1241
|
}
|
1120
1242
|
};
|
1121
1243
|
aRequest.handlers.waitForCallNext = true;
|
1244
|
+
// !!! might need to include X-CSRF-Token see http://stackoverflow.com/questions/8511695/rails-render-json-session-lost?rq=1
|
1122
1245
|
var ajaxpars = {
|
1123
1246
|
type: 'POST',
|
1124
1247
|
data: JSON.stringify(dataToSend),
|
@@ -1131,25 +1254,183 @@ Kojac.RemoteProvider = Kojac.Object.extend({
|
|
1131
1254
|
for (var i=0;i<server_ops.length;i++) {
|
1132
1255
|
var opRequest = server_ops[i]; //aRequest.ops[request_op_index[i]];
|
1133
1256
|
var opResult = (_.isArray(aResult.ops) && (i<aResult.ops.length) && aResult.ops[i]);
|
1134
|
-
opRequest.receiveResult(opResult);
|
1135
1257
|
opRequest.fromCache = false;
|
1136
1258
|
opRequest.performed = true;
|
1259
|
+
if (opResult.error) {
|
1260
|
+
opRequest.error = opResult.error;
|
1261
|
+
aRequest.handlers.handleError(opResult.error);
|
1262
|
+
break;
|
1263
|
+
} else {
|
1264
|
+
opRequest.receiveResult(opResult);
|
1265
|
+
}
|
1137
1266
|
}
|
1138
1267
|
aRequest.handlers.callNext();
|
1139
1268
|
}).fail(function(aXhr,aStatus,aError){
|
1269
|
+
aRequest.error = me.interpretXhrError(aXhr);
|
1270
|
+
//_.removeKey(aRequest,'results');
|
1140
1271
|
for (var i=0;i<server_ops.length;i++) {
|
1141
1272
|
var opRequest = server_ops[i]; //aRequest.ops[request_op_index[i]];
|
1142
1273
|
opRequest.fromCache = false;
|
1143
1274
|
opRequest.performed = true;
|
1275
|
+
//if (opRequest.error)
|
1276
|
+
// _.removeKey(opRequest,'results');
|
1144
1277
|
}
|
1145
|
-
aRequest.error
|
1146
|
-
aRequest.handlers.handleError(aXhr);
|
1278
|
+
aRequest.handlers.handleError(aRequest.error);
|
1147
1279
|
aRequest.handlers.callNext();
|
1148
1280
|
});
|
1149
1281
|
}
|
1282
|
+
},
|
1283
|
+
|
1284
|
+
interpretXhrError: function(aXhr) {
|
1285
|
+
var http_code = null;
|
1286
|
+
var kind = null;
|
1287
|
+
var message = null;
|
1288
|
+
var debug_message = null;
|
1289
|
+
var response = null;
|
1290
|
+
var headers = null;
|
1291
|
+
if (http_code = (aXhr && aXhr.status)) {
|
1292
|
+
kind = (aXhr.statusText && aXhr.statusText.replace(' ',''));
|
1293
|
+
message = debug_message = aXhr.statusText;
|
1294
|
+
headers = aXhr.getAllResponseHeaders();
|
1295
|
+
response = aXhr.responseText;
|
1296
|
+
} else {
|
1297
|
+
http_code = null;
|
1298
|
+
kind = "NetworkError";
|
1299
|
+
message = "Failed to connect. Please check network or try again";
|
1300
|
+
debug_message = "Network connection failed";
|
1301
|
+
}
|
1302
|
+
return {
|
1303
|
+
format: 'KojacError',
|
1304
|
+
http_code: http_code, // a valid HTTP status code, or null
|
1305
|
+
kind: kind, // CamelCase text name of error, for conditional code handling
|
1306
|
+
message: message, // an explanation for normal humans
|
1307
|
+
debug_message: debug_message, // an explanation for developers
|
1308
|
+
xhr: aXhr, // the original XHR object from jQuery
|
1309
|
+
headers: headers, // all response headers
|
1310
|
+
response: response // the response body
|
1311
|
+
}
|
1150
1312
|
}
|
1151
1313
|
});
|
1152
1314
|
|
1315
|
+
|
1316
|
+
Kojac.LocalStorageRemoteProvider = Kojac.Object.extend({
|
1317
|
+
operationsToJson: function(aOps) {
|
1318
|
+
var result = [];
|
1319
|
+
for (var i=0;i<aOps.length;i++) {
|
1320
|
+
var op = aOps[i];
|
1321
|
+
var jsonOp = {
|
1322
|
+
verb: op.verb,
|
1323
|
+
key: op.key
|
1324
|
+
};
|
1325
|
+
if ((op.verb==='CREATE') || (op.verb==='UPDATE') || (op.verb==='EXECUTE')) {
|
1326
|
+
jsonOp.value = Kojac.Utils.toJsono(op.value,op.options);
|
1327
|
+
}
|
1328
|
+
var options = (op.options && _.omit(op.options,['cacheResults','preferCache']));
|
1329
|
+
if (options && !_.isEmpty(options))
|
1330
|
+
jsonOp.options = options; // omit local keys
|
1331
|
+
jsonOp.params = op.params;
|
1332
|
+
result.push(jsonOp);
|
1333
|
+
}
|
1334
|
+
return result
|
1335
|
+
},
|
1336
|
+
|
1337
|
+
handleRequest: function(aRequest) {
|
1338
|
+
var aRequestOp;
|
1339
|
+
if (!aRequest.ops.length)
|
1340
|
+
return;
|
1341
|
+
var ops = this.operationsToJson(aRequest.ops);
|
1342
|
+
var op_output;
|
1343
|
+
var v,op,id,key,value,parts,results,result_key;
|
1344
|
+
for (var i=0;i<ops.length;i++) {
|
1345
|
+
op = ops[i];
|
1346
|
+
aRequestOp = aRequest.ops[i];
|
1347
|
+
if (op.verb=='CREATE') {
|
1348
|
+
id = Kojac.Utils.createId();
|
1349
|
+
key = keyJoin(op.key,id);
|
1350
|
+
result_key = (op.result_key || key);
|
1351
|
+
value = _.clone(op.value,true,true);
|
1352
|
+
value.id = id;
|
1353
|
+
|
1354
|
+
$.jStorage.set(key,value);
|
1355
|
+
results = {};
|
1356
|
+
results[result_key] = value;
|
1357
|
+
op_output = {
|
1358
|
+
key: op.key,
|
1359
|
+
verb: op.verb,
|
1360
|
+
result_key: result_key,
|
1361
|
+
results: results
|
1362
|
+
};
|
1363
|
+
} else if (op.verb=='READ') {
|
1364
|
+
result_key = (op.result_key || op.key);
|
1365
|
+
results = {};
|
1366
|
+
parts = keySplit(op.key);
|
1367
|
+
if (parts[1]) { // item
|
1368
|
+
value = $.jStorage.get(op.key,Boolean);
|
1369
|
+
if (value===Boolean)
|
1370
|
+
value = undefined;
|
1371
|
+
results[result_key] = value;
|
1372
|
+
} else { // collection
|
1373
|
+
var keys = $.jStorage.index();
|
1374
|
+
var ids = [];
|
1375
|
+
_.each(keys,function(k){
|
1376
|
+
parts = keySplit(k);
|
1377
|
+
id = parts[1];
|
1378
|
+
if (parts[0]!=op.key || !id)
|
1379
|
+
return;
|
1380
|
+
ids.push(id);
|
1381
|
+
v = $.jStorage.get(k,Boolean);
|
1382
|
+
if (value===Boolean)
|
1383
|
+
value = undefined;
|
1384
|
+
results[k] = v;
|
1385
|
+
});
|
1386
|
+
results[result_key] = ids;
|
1387
|
+
}
|
1388
|
+
op_output = {
|
1389
|
+
key: op.key,
|
1390
|
+
verb: op.verb,
|
1391
|
+
result_key: result_key,
|
1392
|
+
results: results
|
1393
|
+
};
|
1394
|
+
} else if (op.verb=='UPDATE') {
|
1395
|
+
value = $.jStorage.get(op.key,Boolean);
|
1396
|
+
if (value===Boolean)
|
1397
|
+
value = undefined;
|
1398
|
+
result_key = (op.result_key || op.key);
|
1399
|
+
if (_.isObjectStrict(value))
|
1400
|
+
_.extend(value,op.value);
|
1401
|
+
else
|
1402
|
+
value = op.value;
|
1403
|
+
$.jStorage.set(op.key,value);
|
1404
|
+
results = {};
|
1405
|
+
results[result_key] = value;
|
1406
|
+
op_output = {
|
1407
|
+
key: op.key,
|
1408
|
+
verb: op.verb,
|
1409
|
+
result_key: result_key,
|
1410
|
+
results: results
|
1411
|
+
};
|
1412
|
+
} else if (op.verb=='DESTROY') {
|
1413
|
+
$.jStorage.deleteKey(op.key);
|
1414
|
+
result_key = (op.result_key || op.key);
|
1415
|
+
results = {};
|
1416
|
+
//results[result_key] = undefined;
|
1417
|
+
op_output = {
|
1418
|
+
key: op.key,
|
1419
|
+
verb: op.verb,
|
1420
|
+
result_key: result_key,
|
1421
|
+
results: results
|
1422
|
+
};
|
1423
|
+
} else {
|
1424
|
+
throw "verb not implemented";
|
1425
|
+
}
|
1426
|
+
aRequestOp.receiveResult(op_output);
|
1427
|
+
aRequestOp.fromCache = false;
|
1428
|
+
aRequestOp.performed = true;
|
1429
|
+
}
|
1430
|
+
}
|
1431
|
+
});
|
1432
|
+
|
1433
|
+
|
1153
1434
|
/**
|
1154
1435
|
* A default ObjectFactory implementation. Your own implementation, or a subclass of this may be used instead.
|
1155
1436
|
* @class Kojac.ObjectFactory
|
@@ -1173,7 +1454,7 @@ Kojac.ObjectFactory = Kojac.Object.extend({
|
|
1173
1454
|
var pair;
|
1174
1455
|
var re;
|
1175
1456
|
var newClass;
|
1176
|
-
for (var i = 0; i < this.matchers.length; i++) {
|
1457
|
+
if (this.matchers) for (var i = 0; i < this.matchers.length; i++) {
|
1177
1458
|
pair = this.matchers[i];
|
1178
1459
|
re = pair[0];
|
1179
1460
|
if (!re.test(aKey))
|
@@ -1209,21 +1490,8 @@ Kojac.ObjectFactory = Kojac.Object.extend({
|
|
1209
1490
|
var newClass = this.classFromKey(aKey);
|
1210
1491
|
result = me.createInstance(newClass,aObject);
|
1211
1492
|
}
|
1493
|
+
console.log('END manufacture');
|
1212
1494
|
return result;
|
1213
|
-
},
|
1214
|
-
|
1215
|
-
transformResultsToValueObjects: function(aRequest) {
|
1216
|
-
for (var i=0;i<aRequest.ops.length;i++) {
|
1217
|
-
var op = aRequest.ops[i];
|
1218
|
-
if (op.error)
|
1219
|
-
break;
|
1220
|
-
for (var k in op.results) {
|
1221
|
-
var v = op.results[k];
|
1222
|
-
if (!jQuery.isPlainObject(v))
|
1223
|
-
continue;
|
1224
|
-
op.results[k] = this.manufacture(v,k);
|
1225
|
-
}
|
1226
|
-
}
|
1227
1495
|
}
|
1228
1496
|
|
1229
1497
|
});
|