Commits

Kenneth Jørgensen committed d6a41e4

Loader no longer calls loadRelations automatically. HasOneRelation returns the id if model is not available, in the same way HasManyRelation returns a collection which may contain IDs

Comments (0)

Files changed (5)

-/*! Discrete 0.1.0-dev.7 - MIT license */
+/*! Discrete 0.1.0-dev.8 - MIT license */
 (function() {
   var Async, Calamity, Collection, Discrete, HasManyRelation, HasOneRelation, Loader, Map, Model, ModelRepo, Persistor, Relation, RepoPersistor, Set, SortedMap, calamity, exports, object_toString, root, _, _ref, _ref1,
     __hasProp = {}.hasOwnProperty,
   }
 
   Discrete = {
-    version: "0.1.0-dev.7"
+    version: "0.1.0-dev.8"
   };
 
   if (typeof exports !== "undefined") {
     };
 
     HasOneRelation.prototype.get = function() {
-      return this.model();
+      return this.model() || this.id();
     };
 
     HasOneRelation.prototype.empty = function() {
     };
 
     Loader.prototype.load = function(done) {
-      var model, name, queue, worker, _ref2, _results,
+      var model, name, queue, task, worker, _ref2, _results,
         _this = this;
       this.running = true;
       worker = function(task, done) {
           }
         });
         handlers.push(function(model, done) {
-          if (model.relationsLoaded()) {
-            return done(null, model);
-          } else {
-            return model.loadRelations(function(err) {
-              if (err) {
-                done(err);
-                return;
-              }
-              return done(null, model);
-            });
-          }
-        });
-        handlers.push(function(model, done) {
           if (_.isFunction(_this._poll)) {
             _this._poll(_this, task.name, model);
           }
-          return done();
+          return done(null);
         });
         return Async.waterfall(handlers, function(err) {
           if (err) {
       for (name in _ref2) {
         if (!__hasProp.call(_ref2, name)) continue;
         model = _ref2[name];
-        _results.push(queue.push({
+        task = {
           name: name,
           model: model
+        };
+        _results.push(queue.push(task, function(err) {
+          if (err) {
+            return done(err);
+          }
         }));
       }
       return _results;

spec/LoaderSpec.coffee

 		m1.set
 			forward: m2.id()
 		m2.set
+			back: m1.id()
 			forward: m3.id()
-			back: m1.id()
 		m3.set
 			back: m2.id()
 		# Loader.
 
 	it "should load IDs, load relations, and poll on completion", ->
 		loader.add m1: "id:111"
+		# Create spies on the loadRelation functions.
+		m1loadRelations = sinon.spy m1, "loadRelations"
+		m2loadRelations = sinon.spy m2, "loadRelations"
+		m3loadRelations = sinon.spy m3, "loadRelations"
+		# When m1 is loaded, add the forward relation, which is m2.
 		loader.poll poll = sinon.spy (loader, name, model) ->
 			if name is "m1"
-				loader.add m2: model.get "forward"
+				id = model.getRelation("forward").id()
+				loader.add m2: id
 		loader.load done
 		waitsFor (-> done.called), "Done never called", 100
 		runs ->
-			# Done.
+			# Loader should never call loadRelations.
+			expect(m1loadRelations.callCount).toBe 0
+			expect(m2loadRelations.callCount).toBe 0
+			expect(m3loadRelations.callCount).toBe 0
+			# Done should be called once with no error and the loader as argument.
 			expect(done.callCount).toBe 1
 			expect(done.args[0][0]).toBe null
 			expect(done.args[0][1]).toBe loader
-			# Poll.
+			# Poll should be called twice, once with `m1` and one with `m2`.
 			expect(poll.callCount).toBe 2
 			expect(poll.args[0][0]).toBe loader
 			expect(poll.args[0][1]).toBe "m1"
 			expect(poll.args[1][0]).toBe loader
 			expect(poll.args[1][1]).toBe "m2"
 			expect(poll.args[1][2]).toBe m2
-			# Check relations.
-			expect(m1.relationsLoaded()).toBe true
-			expect(m2.relationsLoaded()).toBe true
-			expect(m3.relationsLoaded()).toBe false # m3 was never explicitly added, and thus not loaded.
-			# Saved.
+			# `m1` relations.
+#			expect(m1.get "forward").toBe m2 # loaded explicitly.
+#			expect(m1.relationsLoaded()).toBe true # m2 was added explicitly.
+			# `m2` relations.
+#			expect(m2.get "back").toBe m1 # loaded explicitly.
+#			expect(m2.get "forward").toBe m3.id() # not loaded explicitly.
+#			expect(m2.relationsLoaded()).toBe false # m1 was added, but m3 wasn't.
+			# `m3` relations.
+#			expect(m3.get "back").toBe m2.id() # not loaded explicitly. Theoretically this should come from the repo or something. Future feature.
+#			expect(m3.relationsLoaded()).toBe false # m3 was never explicitly added, and thus not loaded.
+			# Check contents.
 			expect(loader.get "m1").toBe m1
 			expect(loader.get "m2").toBe m2
+			expect(loader.get "m3").toBe undefined
 
 	it "should not start fetching more models when loading is completed", ->
 		loader.load done

spec/Relation/HasOneRelationSpec.coffee

 		expect(relation.empty()).toBe false
 		expect(relation.id()).toBe 42
 		expect(relation.model()).toBe null
-		expect(relation.get()).toBe null
+		expect(relation.get()).toBe 42
 		# Strings
 		relation.set "id:42"
 		expect(relation.loaded()).toBe false
 			data = change.getCall(0).args[0].data
 			expect(data.relation).toBe relation
 			expect(data.id).toBe 1
-			expect(data.value).toBe null
+			expect(data.value).toBe 1
 
 	it "should fire change events when setting a model", ->
 		m1 = new Model id:1
 			expect(clone).not.toBe relation
 			expect(clone.id()).toBe 1
 			expect(clone.model()).toBe null
-			expect(clone.get()).toBe null
+			expect(clone.get()).toBe 1
 			# Modify from original, should not affect clone.
 			relation.set 2
 			expect(clone.id()).toBe 1

src/Loader.coffee

 			map[models] = models
 		else
 			throw new Error "Models must be either Collection, array, Map, Model, Object, or string or number, '#{typeof models}' supplied"
-		# Everything valid has now been converted to a simple map object, add it all to be loaded.
+		# Everything valid has now been converted to a simple hashmap, add it all to be loaded.
 		for own name, model of map
 			if _.isObject(model) and not (model instanceof Model)
 				throw new Error "Non-model object supplied for model"
 						@_models[task.name] = model
 						# Pass.
 						done null, model
-			# Next we need to load the relation of the model.
-			handlers.push (model, done) =>
-				if model.relationsLoaded()
-					done null, model
-				else
-					model.loadRelations (err) =>
-						if err
-							done err
-							return
-						done null, model
 			# Finally we need to supply the prepared model to the polling function.
 			handlers.push (model, done) =>
 				@_poll @, task.name, model if _.isFunction @_poll
-				done()
+				done null
 			# Execute task.
 			Async.waterfall handlers, (err) =>
 				if err
 			done null, @ # @todo catch errors
 		# Populate queue with initial tasks.
 		for own name, model of @_models
-			queue.push
+			task =
 				name: name
 				model: model
+			queue.push task, (err) =>
+				if err
+					done err
 
 	# Saves all the known models.
 	saveAll: (done) ->

src/Relation/HasOneRelation.coffee

 	model: ->
 		return @_model
 
-	get: -> @model()
+	get: ->
+		return @model() or @id()
 
 	# Returns true if this relation doesn't point to a foreign model.
 	empty: ->