{"action":"created","comment":{"url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/pulls/comments/70291853","id":70291853,"diff_hunk":"@@ -2783,192 +2836,308 @@ DataAccessObject.replaceById = function(id, data, options, cb) {\n  * @param {Function} cb Callback function called with (err, instance)\n  */\n DataAccessObject.prototype.updateAttributes =\n-DataAccessObject.prototype.patchAttributes =\n-function(data, options, cb) {\n-  var self = this;\n+  DataAccessObject.prototype.patchAttributes =\n+    function(data, options, cb) {\n+      var self = this;\n+      var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);\n+      if (connectionPromise) {\n+        return connectionPromise;\n+      }\n+\n+      if (options === undefined && cb === undefined) {\n+        if (typeof data === 'function') {\n+          // updateAttributes(cb)\n+          cb = data;\n+          data = undefined;\n+        }\n+      } else if (cb === undefined) {\n+        if (typeof options === 'function') {\n+          // updateAttributes(data, cb)\n+          cb = options;\n+          options = {};\n+        }\n+      }\n+\n+      cb = cb || utils.createPromiseCallback();\n+      options = options || {};\n+\n+      assert((typeof data === 'object') && (data !== null),\n+        'The data argument must be an object');\n+      assert(typeof options === 'object', 'The options argument must be an object');\n+      assert(typeof cb === 'function', 'The cb argument must be a function');\n+\n+      var inst = this;\n+      var Model = this.constructor;\n+      var connector = inst.getConnector();\n+      assert(typeof connector.updateAttributes === 'function',\n+        'updateAttributes() must be implemented by the connector');\n+\n+      if (isPKMissing(Model, cb))\n+        return cb.promise;\n+\n+      var allowExtendedOperators = connector.settings &&\n+        connector.settings.allowExtendedOperators;\n+\n+      var strict = this.__strict;\n+      var model = Model.modelName;\n+      var hookState = {};\n+\n+      // Convert the data to be plain object so that update won't be confused\n+      if (data instanceof Model) {\n+        data = data.toObject(false);\n+      }\n+      data = removeUndefined(data);\n+\n+      // Make sure id(s) cannot be changed\n+      var idNames = Model.definition.idNames();\n+      for (var i = 0, n = idNames.length; i < n; i++) {\n+        var idName = idNames[i];\n+        if (data[idName] !== undefined && !idEquals(data[idName], inst[idName])) {\n+          var err = new Error('id property (' + idName + ') ' +\n+            'cannot be updated from ' + inst[idName] + ' to ' + data[idName]);\n+          err.statusCode = 400;\n+          process.nextTick(function() {\n+            cb(err);\n+          });\n+          return cb.promise;\n+        }\n+      }\n+\n+      var context = {\n+        Model: Model,\n+        where: byIdQuery(Model, getIdValue(Model, inst)).where,\n+        data: data,\n+        currentInstance: inst,\n+        hookState: hookState,\n+        options: options,\n+      };\n+\n+      Model.notifyObserversOf('before save', context, function(err, ctx) {\n+        if (err) return cb(err);\n+        data = ctx.data;\n+\n+        if (strict && !allowExtendedOperators) {\n+          applyStrictCheck(self.constructor, strict, data, inst, validateAndSave);\n+        } else {\n+          validateAndSave(null, data);\n+        }\n+\n+        function validateAndSave(err, data) {\n+          if (err) return cb(err);\n+          data = removeUndefined(data);\n+          var doValidate = true;\n+          if (options.validate === undefined) {\n+            if (Model.settings.automaticValidation !== undefined) {\n+              doValidate = Model.settings.automaticValidation;\n+            }\n+          } else {\n+            doValidate = options.validate;\n+          }\n+\n+          // update instance's properties\n+          inst.setAttributes(data);\n+\n+          if (doValidate) {\n+            inst.isValid(function(valid) {\n+              if (!valid) {\n+                cb(new ValidationError(inst), inst);\n+                return;\n+              }\n+\n+              triggerSave();\n+            }, data, options);\n+          } else {\n+            triggerSave();\n+          }\n+\n+          function triggerSave() {\n+            inst.trigger('save', function(saveDone) {\n+              inst.trigger('update', function(done) {\n+                copyData(data, inst);\n+                var typedData = convertSubsetOfPropertiesByType(inst, data);\n+                context.data = typedData;\n+\n+                function updateAttributesCallback(err) {\n+                  if (err) return cb(err);\n+                  var ctx = {\n+                    Model: Model,\n+                    data: context.data,\n+                    hookState: hookState,\n+                    options: options,\n+                  };\n+                  Model.notifyObserversOf('loaded', ctx, function(err) {\n+                    if (err) return cb(err);\n+\n+                    inst.__persisted = true;\n+\n+                    // By default, the instance passed to updateAttributes callback is NOT updated\n+                    // with the changes made through persist/loaded hooks. To preserve\n+                    // backwards compatibility, we introduced a new setting updateOnLoad,\n+                    // which if set, will apply these changes to the model instance too.\n+                    if (Model.settings.updateOnLoad) {\n+                      inst.setAttributes(ctx.data);\n+                    }\n+                    done.call(inst, function() {\n+                      saveDone.call(inst, function() {\n+                        if (err) return cb(err, inst);\n+\n+                        var context = {\n+                          Model: Model,\n+                          instance: inst,\n+                          isNewInstance: false,\n+                          hookState: hookState,\n+                          options: options,\n+                        };\n+                        Model.notifyObserversOf('after save', context, function(err) {\n+                          cb(err, inst);\n+                        });\n+                      });\n+                    });\n+                  });\n+                }\n+\n+                var ctx = {\n+                  Model: Model,\n+                  where: byIdQuery(Model, getIdValue(Model, inst)).where,\n+                  data: context.data,\n+                  currentInstance: inst,\n+                  isNewInstance: false,\n+                  hookState: hookState,\n+                  options: options,\n+                };\n+                Model.notifyObserversOf('persist', ctx, function(err) {\n+                  if (connector.updateAttributes.length === 5) {\n+                    connector.updateAttributes(model, getIdValue(inst.constructor, inst),\n+                      inst.constructor._forDB(context.data), options, updateAttributesCallback);\n+                  } else {\n+                    connector.updateAttributes(model, getIdValue(inst.constructor, inst),\n+                      inst.constructor._forDB(context.data), updateAttributesCallback);\n+                  }\n+                });\n+              }, data, cb);\n+            }, data, cb);\n+          }\n+        }\n+      });\n+      return cb.promise;\n+    };\n+/**\n+ * Performs upsert based on the instance that matches the where clause\n+ . This is a PUT operation and based on\n+ * non-primary key. The filter takes one key value pair and updates single matching instance.*\n+ */\n+\n+\n+DataAccessObject.upsertWithWhere = function(where, data, options, cb) {\n+\n   var connectionPromise = stillConnecting(this.getDataSource(), this, arguments);\n   if (connectionPromise) {\n     return connectionPromise;\n   }\n-\n-  if (options === undefined && cb === undefined) {\n+  assert(arguments.length >= 1, 'At least one argument is required');\n+  if (data === undefined && options === undefined && cb === undefined && arguments.length === 1) {\n+    data = where;\n+    where = {};\n+  } else if (options === undefined && cb === undefined) {\n     if (typeof data === 'function') {\n-      // updateAttributes(cb)\n       cb = data;\n-      data = undefined;\n+      data = where;\n+      where = {};\n     }\n   } else if (cb === undefined) {\n     if (typeof options === 'function') {\n-      // updateAttributes(data, cb)\n       cb = options;\n       options = {};\n     }\n   }\n-\n-  cb = cb || utils.createPromiseCallback();\n+  data = data || {};\n   options = options || {};\n-\n-  assert((typeof data === 'object') && (data !== null),\n-    'The data argument must be an object');\n+  cb = cb || utils.createPromiseCallback();\n+  assert(typeof where === 'object', 'The where argument must be an object');\n+  assert(typeof data === 'object', 'The data argument must be an object');\n   assert(typeof options === 'object', 'The options argument must be an object');\n   assert(typeof cb === 'function', 'The cb argument must be a function');\n-\n-  var inst = this;\n-  var Model = this.constructor;\n-  var connector = inst.getConnector();\n-  assert(typeof connector.updateAttributes === 'function',\n-    'updateAttributes() must be implemented by the connector');\n-\n-  if (isPKMissing(Model, cb))\n-    return cb.promise;\n-\n-  var allowExtendedOperators = connector.settings &&\n-    connector.settings.allowExtendedOperators;\n-\n-  var strict = this.__strict;\n-  var model = Model.modelName;\n   var hookState = {};\n+  var self = this;\n+  var Model=this;\n+  var connector = Model.getConnector();\n \n-  // Convert the data to be plain object so that update won't be confused\n-  if (data instanceof Model) {\n-    data = data.toObject(false);\n-  }\n-  data = removeUndefined(data);\n-\n-  // Make sure id(s) cannot be changed\n-  var idNames = Model.definition.idNames();\n-  for (var i = 0, n = idNames.length; i < n; i++) {\n-    var idName = idNames[i];\n-    if (data[idName] !== undefined && !idEquals(data[idName], inst[idName])) {\n-      var err = new Error('id property (' + idName + ') ' +\n-        'cannot be updated from ' + inst[idName] + ' to ' + data[idName]);\n-      err.statusCode = 400;\n-      process.nextTick(function() {\n-        cb(err);\n-      });\n-      return cb.promise;\n-    }\n-  }\n+  var element = Object.keys(where)[0];\n+  console.log(element);\n \n-  var context = {\n-    Model: Model,\n-    where: byIdQuery(Model, getIdValue(Model, inst)).where,\n-    data: data,\n-    currentInstance: inst,\n-    hookState: hookState,\n-    options: options,\n+  var filter = {\n+    \"where\": where\n   };\n \n-  Model.notifyObserversOf('before save', context, function(err, ctx) {\n-    if (err) return cb(err);\n-    data = ctx.data;\n-\n-    if (strict && !allowExtendedOperators) {\n-      applyStrictCheck(self.constructor, strict, data, inst, validateAndSave);\n-    } else {\n-      validateAndSave(null, data);\n+  if (Object.keys(data).length != 0) {\n+    if (!data.hasOwnProperty(element)) {\n+      data[element] = where[element];\n     }\n \n-    function validateAndSave(err, data) {\n-      if (err) return cb(err);\n-      data = removeUndefined(data);\n-      var doValidate = true;\n-      if (options.validate === undefined) {\n-        if (Model.settings.automaticValidation !== undefined) {\n-          doValidate = Model.settings.automaticValidation;\n-        }\n-      } else {\n-        doValidate = options.validate;\n-      }\n+    var pk = idName(Model);\n \n-      // update instance's properties\n-      inst.setAttributes(data);\n+    self.find(filter, function (err, instances) {\n \n-      if (doValidate) {\n-        inst.isValid(function(valid) {\n-          if (!valid) {\n-            cb(new ValidationError(inst), inst);\n-            return;\n-          }\n+      var modelsLength = instances.length;\n+      console.log(\"modelsLength\", modelsLength);\n+      if (modelsLength === 0 && data.hasOwnProperty(pk)) {\n+        return self.create(data, options, cb);\n+      }\n \n-          triggerSave();\n-        }, data, options);\n-      } else {\n-        triggerSave();\n+      else if (modelsLength == 0 && data.hasOwnProperty(pk) == false) {\n+\n+        cb(\"Error message: No matching instance found. Found error while trying to create a new instance.Primary key is not provided in the payload\");\n       }\n \n-      function triggerSave() {\n-        inst.trigger('save', function(saveDone) {\n-          inst.trigger('update', function(done) {\n-            copyData(data, inst);\n-            var typedData = convertSubsetOfPropertiesByType(inst, data);\n-            context.data = typedData;\n+      else if (modelsLength === 1) {\n+        var pkName = idName(Model);\n+        console.log(\"idName\", pkName);\n+        var idVal = instances[0][pkName];\n+        self.findById(idVal, function (err, modelInst) {\n+          if (err) {\n+            cb(err);\n+          }\n+          else {\n \n-            function updateAttributesCallback(err) {\n-              if (err) return cb(err);\n-              var ctx = {\n-                Model: Model,\n-                data: context.data,\n-                hookState: hookState,\n-                options: options,\n-              };\n-              Model.notifyObserversOf('loaded', ctx, function(err) {\n-                if (err) return cb(err);\n+            modelInst.updateAttributes(data, function (err, info) {\n \n-                inst.__persisted = true;\n+              if (err) {\n \n-                // By default, the instance passed to updateAttributes callback is NOT updated\n-                // with the changes made through persist/loaded hooks. To preserve\n-                // backwards compatibility, we introduced a new setting updateOnLoad,\n-                // which if set, will apply these changes to the model instance too.\n-                if (Model.settings.updateOnLoad) {\n-                  inst.setAttributes(ctx.data);\n-                }\n-                done.call(inst, function() {\n-                  saveDone.call(inst, function() {\n-                    if (err) return cb(err, inst);\n-\n-                    var context = {\n-                      Model: Model,\n-                      instance: inst,\n-                      isNewInstance: false,\n-                      hookState: hookState,\n-                      options: options,\n-                    };\n-                    Model.notifyObserversOf('after save', context, function(err) {\n-                      cb(err, inst);\n-                    });\n-                  });\n-                });\n-              });\n-            }\n \n-            var ctx = {\n-              Model: Model,\n-              where: byIdQuery(Model, getIdValue(Model, inst)).where,\n-              data: context.data,\n-              currentInstance: inst,\n-              isNewInstance: false,\n-              hookState: hookState,\n-              options: options,\n-            };\n-            Model.notifyObserversOf('persist', ctx, function(err) {\n-              if (connector.updateAttributes.length === 5) {\n-                connector.updateAttributes(model, getIdValue(inst.constructor, inst),\n-                  inst.constructor._forDB(context.data), options, updateAttributesCallback);\n+                cb(err);\n               } else {\n-                connector.updateAttributes(model, getIdValue(inst.constructor, inst),\n-                  inst.constructor._forDB(context.data), updateAttributesCallback);\n+\n+                cb(null, info);\n+\n               }\n+\n+\n             });\n-          }, data, cb);\n-        }, data, cb);\n+\n+          }\n+\n+        });\n+\n+\n       }\n+\n+\n+    else {\n+\n+      cb(\"There are multiple instances found.Upsert Operation can't be performed \");\n     }\n-  });\n-  return cb.promise;\n-};\n+    });\n \n+  }\n+\n+\n+\n+else\n+{\n+cb(\"data field can't be empty\");","path":"lib/dao.js","position":1824,"original_position":1824,"commit_id":"5c4bc2409e2c06669a05aef4d78fa77a853f4d76","original_commit_id":"5c4bc2409e2c06669a05aef4d78fa77a853f4d76","user":{"login":"raymondfeng","id":540892,"avatar_url":"https://avatars.githubusercontent.com/u/540892?v=3","gravatar_id":"","url":"https://api.github.com/users/raymondfeng","html_url":"https://github.com/raymondfeng","followers_url":"https://api.github.com/users/raymondfeng/followers","following_url":"https://api.github.com/users/raymondfeng/following{/other_user}","gists_url":"https://api.github.com/users/raymondfeng/gists{/gist_id}","starred_url":"https://api.github.com/users/raymondfeng/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/raymondfeng/subscriptions","organizations_url":"https://api.github.com/users/raymondfeng/orgs","repos_url":"https://api.github.com/users/raymondfeng/repos","events_url":"https://api.github.com/users/raymondfeng/events{/privacy}","received_events_url":"https://api.github.com/users/raymondfeng/received_events","type":"User","site_admin":false},"body":"Bad style","created_at":"2016-07-11T16:35:14Z","updated_at":"2016-07-11T16:35:14Z","html_url":"https://github.com/strongloop/loopback-datasource-juggler/pull/995#discussion_r70291853","pull_request_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/pulls/995","_links":{"self":{"href":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/pulls/comments/70291853"},"html":{"href":"https://github.com/strongloop/loopback-datasource-juggler/pull/995#discussion_r70291853"},"pull_request":{"href":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/pulls/995"}}},"pull_request":{"url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/pulls/995","id":76928488,"html_url":"https://github.com/strongloop/loopback-datasource-juggler/pull/995","diff_url":"https://github.com/strongloop/loopback-datasource-juggler/pull/995.diff","patch_url":"https://github.com/strongloop/loopback-datasource-juggler/pull/995.patch","issue_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/issues/995","number":995,"state":"open","locked":false,"title":"changes to dao.js and memory.js to add a new method on Upsert based on non-primary key","user":{"login":"mountain1234585","id":18303722,"avatar_url":"https://avatars.githubusercontent.com/u/18303722?v=3","gravatar_id":"","url":"https://api.github.com/users/mountain1234585","html_url":"https://github.com/mountain1234585","followers_url":"https://api.github.com/users/mountain1234585/followers","following_url":"https://api.github.com/users/mountain1234585/following{/other_user}","gists_url":"https://api.github.com/users/mountain1234585/gists{/gist_id}","starred_url":"https://api.github.com/users/mountain1234585/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mountain1234585/subscriptions","organizations_url":"https://api.github.com/users/mountain1234585/orgs","repos_url":"https://api.github.com/users/mountain1234585/repos","events_url":"https://api.github.com/users/mountain1234585/events{/privacy}","received_events_url":"https://api.github.com/users/mountain1234585/received_events","type":"User","site_admin":false},"body":"Hi Raymond,\r\nKindly review the basic changes done to loopback-datasource-juggler lib/dao.js and lib/connectors/memory.js to include a new method called \"upsertWithWhere\" based on non-primary key.\r\n1)This method leverages the existing methods, find, create, findById and updateAttributes.\r\n2)I have not added notifyObserversOf like in other methods , since this method calls them internally.\r\n3)Once you review the code changes, we will add the unit tests as well.\r\n4) I have tested the operation manually by creating an application, memory db datasource and persisted model in case of create and update scenarios.\r\nThanks,\r\nSonali Samantaray","created_at":"2016-07-11T10:06:20Z","updated_at":"2016-07-11T16:35:14Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c8313cde94a57c20949efc510fea6ec4f18f1d37","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/pulls/995/commits","review_comments_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/pulls/995/comments","review_comment_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/pulls/comments{/number}","comments_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/issues/995/comments","statuses_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/statuses/5c4bc2409e2c06669a05aef4d78fa77a853f4d76","head":{"label":"mountain1234585:upsertWithWhere","ref":"upsertWithWhere","sha":"5c4bc2409e2c06669a05aef4d78fa77a853f4d76","user":{"login":"mountain1234585","id":18303722,"avatar_url":"https://avatars.githubusercontent.com/u/18303722?v=3","gravatar_id":"","url":"https://api.github.com/users/mountain1234585","html_url":"https://github.com/mountain1234585","followers_url":"https://api.github.com/users/mountain1234585/followers","following_url":"https://api.github.com/users/mountain1234585/following{/other_user}","gists_url":"https://api.github.com/users/mountain1234585/gists{/gist_id}","starred_url":"https://api.github.com/users/mountain1234585/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mountain1234585/subscriptions","organizations_url":"https://api.github.com/users/mountain1234585/orgs","repos_url":"https://api.github.com/users/mountain1234585/repos","events_url":"https://api.github.com/users/mountain1234585/events{/privacy}","received_events_url":"https://api.github.com/users/mountain1234585/received_events","type":"User","site_admin":false},"repo":{"id":63051048,"name":"loopback-datasource-juggler","full_name":"mountain1234585/loopback-datasource-juggler","owner":{"login":"mountain1234585","id":18303722,"avatar_url":"https://avatars.githubusercontent.com/u/18303722?v=3","gravatar_id":"","url":"https://api.github.com/users/mountain1234585","html_url":"https://github.com/mountain1234585","followers_url":"https://api.github.com/users/mountain1234585/followers","following_url":"https://api.github.com/users/mountain1234585/following{/other_user}","gists_url":"https://api.github.com/users/mountain1234585/gists{/gist_id}","starred_url":"https://api.github.com/users/mountain1234585/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mountain1234585/subscriptions","organizations_url":"https://api.github.com/users/mountain1234585/orgs","repos_url":"https://api.github.com/users/mountain1234585/repos","events_url":"https://api.github.com/users/mountain1234585/events{/privacy}","received_events_url":"https://api.github.com/users/mountain1234585/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mountain1234585/loopback-datasource-juggler","description":"Connect Loopback to various Data Sources","fork":true,"url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler","forks_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/forks","keys_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/teams","hooks_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/hooks","issue_events_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/issues/events{/number}","events_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/events","assignees_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/assignees{/user}","branches_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/branches{/branch}","tags_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/tags","blobs_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/git/refs{/sha}","trees_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/statuses/{sha}","languages_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/languages","stargazers_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/stargazers","contributors_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/contributors","subscribers_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/subscribers","subscription_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/subscription","commits_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/commits{/sha}","git_commits_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/git/commits{/sha}","comments_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/comments{/number}","issue_comment_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/issues/comments{/number}","contents_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/contents/{+path}","compare_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/merges","archive_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/downloads","issues_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/issues{/number}","pulls_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/pulls{/number}","milestones_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/milestones{/number}","notifications_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/labels{/name}","releases_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/releases{/id}","deployments_url":"https://api.github.com/repos/mountain1234585/loopback-datasource-juggler/deployments","created_at":"2016-07-11T08:35:42Z","updated_at":"2016-07-11T08:35:43Z","pushed_at":"2016-07-11T09:00:40Z","git_url":"git://github.com/mountain1234585/loopback-datasource-juggler.git","ssh_url":"git@github.com:mountain1234585/loopback-datasource-juggler.git","clone_url":"https://github.com/mountain1234585/loopback-datasource-juggler.git","svn_url":"https://github.com/mountain1234585/loopback-datasource-juggler","homepage":"http://www.loopback.io","size":5648,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"strongloop:master","ref":"master","sha":"45e14af4a981fcf376276babeb344ceac578186c","user":{"login":"strongloop","id":3020012,"avatar_url":"https://avatars.githubusercontent.com/u/3020012?v=3","gravatar_id":"","url":"https://api.github.com/users/strongloop","html_url":"https://github.com/strongloop","followers_url":"https://api.github.com/users/strongloop/followers","following_url":"https://api.github.com/users/strongloop/following{/other_user}","gists_url":"https://api.github.com/users/strongloop/gists{/gist_id}","starred_url":"https://api.github.com/users/strongloop/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/strongloop/subscriptions","organizations_url":"https://api.github.com/users/strongloop/orgs","repos_url":"https://api.github.com/users/strongloop/repos","events_url":"https://api.github.com/users/strongloop/events{/privacy}","received_events_url":"https://api.github.com/users/strongloop/received_events","type":"Organization","site_admin":false},"repo":{"id":10126908,"name":"loopback-datasource-juggler","full_name":"strongloop/loopback-datasource-juggler","owner":{"login":"strongloop","id":3020012,"avatar_url":"https://avatars.githubusercontent.com/u/3020012?v=3","gravatar_id":"","url":"https://api.github.com/users/strongloop","html_url":"https://github.com/strongloop","followers_url":"https://api.github.com/users/strongloop/followers","following_url":"https://api.github.com/users/strongloop/following{/other_user}","gists_url":"https://api.github.com/users/strongloop/gists{/gist_id}","starred_url":"https://api.github.com/users/strongloop/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/strongloop/subscriptions","organizations_url":"https://api.github.com/users/strongloop/orgs","repos_url":"https://api.github.com/users/strongloop/repos","events_url":"https://api.github.com/users/strongloop/events{/privacy}","received_events_url":"https://api.github.com/users/strongloop/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/strongloop/loopback-datasource-juggler","description":"Connect Loopback to various Data Sources","fork":false,"url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler","forks_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/forks","keys_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/keys{/key_id}","collaborators_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/teams","hooks_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/hooks","issue_events_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/issues/events{/number}","events_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/events","assignees_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/assignees{/user}","branches_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/branches{/branch}","tags_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/tags","blobs_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/git/refs{/sha}","trees_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/git/trees{/sha}","statuses_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/statuses/{sha}","languages_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/languages","stargazers_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/stargazers","contributors_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/contributors","subscribers_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/subscribers","subscription_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/subscription","commits_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/commits{/sha}","git_commits_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/git/commits{/sha}","comments_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/comments{/number}","issue_comment_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/issues/comments{/number}","contents_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/contents/{+path}","compare_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/compare/{base}...{head}","merges_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/merges","archive_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/downloads","issues_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/issues{/number}","pulls_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/pulls{/number}","milestones_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/milestones{/number}","notifications_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/labels{/name}","releases_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/releases{/id}","deployments_url":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/deployments","created_at":"2013-05-17T15:56:04Z","updated_at":"2016-06-28T18:45:59Z","pushed_at":"2016-07-11T15:26:20Z","git_url":"git://github.com/strongloop/loopback-datasource-juggler.git","ssh_url":"git@github.com:strongloop/loopback-datasource-juggler.git","clone_url":"https://github.com/strongloop/loopback-datasource-juggler.git","svn_url":"https://github.com/strongloop/loopback-datasource-juggler","homepage":"http://www.loopback.io","size":6211,"stargazers_count":138,"watchers_count":138,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":193,"mirror_url":null,"open_issues_count":208,"forks":193,"open_issues":208,"watchers":138,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/pulls/995"},"html":{"href":"https://github.com/strongloop/loopback-datasource-juggler/pull/995"},"issue":{"href":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/issues/995"},"comments":{"href":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/issues/995/comments"},"review_comments":{"href":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/pulls/995/comments"},"review_comment":{"href":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/pulls/995/commits"},"statuses":{"href":"https://api.github.com/repos/strongloop/loopback-datasource-juggler/statuses/5c4bc2409e2c06669a05aef4d78fa77a853f4d76"}}}}
{"actor":{"display_login":"raymondfeng"}}