{"action":"created","comment":{"url":"https://api.github.com/repos/sequelize/sequelize/pulls/comments/83343984","pull_request_review_id":4194151,"id":83343984,"diff_hunk":"@@ -780,12 +788,21 @@ class Model {\n         this._timestampAttributes.deletedAt = this.options.deletedAt || Utils.underscoredIf('deletedAt', this.options.underscored);\n       }\n     }\n+    if (this.options.version) {\n+      if (typeof(this.options.version) === 'string') {","path":"lib/model.js","position":20,"original_position":20,"commit_id":"b37fcf1d2368c5f0c1db908b0ddb8ff14d1c6ce3","original_commit_id":"b37fcf1d2368c5f0c1db908b0ddb8ff14d1c6ce3","user":{"login":"SimonSchick","id":3259089,"avatar_url":"https://avatars.githubusercontent.com/u/3259089?v=3","gravatar_id":"","url":"https://api.github.com/users/SimonSchick","html_url":"https://github.com/SimonSchick","followers_url":"https://api.github.com/users/SimonSchick/followers","following_url":"https://api.github.com/users/SimonSchick/following{/other_user}","gists_url":"https://api.github.com/users/SimonSchick/gists{/gist_id}","starred_url":"https://api.github.com/users/SimonSchick/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SimonSchick/subscriptions","organizations_url":"https://api.github.com/users/SimonSchick/orgs","repos_url":"https://api.github.com/users/SimonSchick/repos","events_url":"https://api.github.com/users/SimonSchick/events{/privacy}","received_events_url":"https://api.github.com/users/SimonSchick/received_events","type":"User","site_admin":false},"body":"From what I can tell most of the project does not use function style `typeof`.","created_at":"2016-10-14T01:10:32Z","updated_at":"2016-10-14T01:10:32Z","html_url":"https://github.com/sequelize/sequelize/pull/6637#discussion_r83343984","pull_request_url":"https://api.github.com/repos/sequelize/sequelize/pulls/6637","_links":{"self":{"href":"https://api.github.com/repos/sequelize/sequelize/pulls/comments/83343984"},"html":{"href":"https://github.com/sequelize/sequelize/pull/6637#discussion_r83343984"},"pull_request":{"href":"https://api.github.com/repos/sequelize/sequelize/pulls/6637"}}},"pull_request":{"url":"https://api.github.com/repos/sequelize/sequelize/pulls/6637","id":86832015,"html_url":"https://github.com/sequelize/sequelize/pull/6637","diff_url":"https://github.com/sequelize/sequelize/pull/6637.diff","patch_url":"https://github.com/sequelize/sequelize/pull/6637.patch","issue_url":"https://api.github.com/repos/sequelize/sequelize/issues/6637","number":6637,"state":"open","locked":false,"title":"Implement optimistic locking","user":{"login":"davidtsai","id":1231648,"avatar_url":"https://avatars.githubusercontent.com/u/1231648?v=3","gravatar_id":"","url":"https://api.github.com/users/davidtsai","html_url":"https://github.com/davidtsai","followers_url":"https://api.github.com/users/davidtsai/followers","following_url":"https://api.github.com/users/davidtsai/following{/other_user}","gists_url":"https://api.github.com/users/davidtsai/gists{/gist_id}","starred_url":"https://api.github.com/users/davidtsai/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/davidtsai/subscriptions","organizations_url":"https://api.github.com/users/davidtsai/orgs","repos_url":"https://api.github.com/users/davidtsai/repos","events_url":"https://api.github.com/users/davidtsai/events{/privacy}","received_events_url":"https://api.github.com/users/davidtsai/received_events","type":"User","site_admin":false},"body":"Add support for optimistic locking directly into _Sequelize_. Related discussion: #6617 \r\n\r\n## Why Sequelize should support optimistic locking\r\n\r\nOptimistic locking is a widely accepted best practice to prevent data from being clobbered when multiple requests/processes/hosts attempt to write the same model instance.  Optimistic locking makes it easier to write concurrency safe application code using Sequelize without being an expert on database transactions and read isolation semantics.  In addition to that, optimistic locking is superior because it is less likely to cause deadlocks as compared to transaction based pessimistic locking.\r\n\r\n## Why this should not be a plugin\r\n\r\n- The practical reason for this not being a plugin is because it can't be implemented under the current plugin architecture.  The update query needs to commit the update and increment the version number only if the version matches the version stored in the model instance.  The current hooks provided does not allow this be accomplished because you cannot modify the update query directly and it also does not return how many rows were affected in the update.\r\n\r\n- The second high level reason is that `Sequelize`should support this as a first class citizen because it is a widely used best practice that competing ORMs on different platforms support.\r\n\r\n## What this PR does\r\n\r\n- It adds an option to model definitions named `version` that turns on optimistic locking for the model by adding a version number attribute.\r\n- When optimistic locking is turned on for a model, updates to a model instance will throw an error if the application does not have a current copy of the model instance.  Example:\r\n```javascript\r\nvar one = await Model.create();\r\nvar two = Model.findById(one.id);\r\none.value = 1;\r\nawait one.save(); // Succeeds\r\ntwo.value = 2;\r\nawait two.save(); // Throws `OptimisticLockError` because two is a stale copy\r\n```\r\nTo make the example above succeed you would have to reload the model:\r\n```javascript\r\nvar one = await Model.create();\r\nvar two = Model.findById(one.id);\r\none.value = 1;\r\nawait one.save(); // Succeeds\r\nawait two.reload();\r\ntwo.value = 2;\r\nawait two.save(); // Succeeds\r\n```\r\n\r\nP.S. Thanks for reading and for creating and maintaining Sequelize!\r\n\r\n### Pull Request check-list\r\n\r\n_Please make sure to review and check all of these items:_\r\n\r\n- [x] Does `npm run test` or `npm run test-DIALECT` pass with this change (including linting)?\r\n- [x] Does your issue contain a link to existing issue (Closes #[issue]) or a description of the issue you are solving?\r\n- [x] Have you added new tests to prevent regressions?\r\n- [x] Is a documentation update included (if this change modifies existing APIs, or introduces new ones)?\r\n- [x] Have you added an entry under `Future` in the changelog?\r\n\r\n","created_at":"2016-09-26T22:38:12Z","updated_at":"2016-10-14T01:14:06Z","closed_at":null,"merged_at":null,"merge_commit_sha":"00cb33c4a9222744c3b497729efcd22885597d49","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/sequelize/sequelize/pulls/6637/commits","review_comments_url":"https://api.github.com/repos/sequelize/sequelize/pulls/6637/comments","review_comment_url":"https://api.github.com/repos/sequelize/sequelize/pulls/comments{/number}","comments_url":"https://api.github.com/repos/sequelize/sequelize/issues/6637/comments","statuses_url":"https://api.github.com/repos/sequelize/sequelize/statuses/b37fcf1d2368c5f0c1db908b0ddb8ff14d1c6ce3","head":{"label":"convoyinc:master","ref":"master","sha":"b37fcf1d2368c5f0c1db908b0ddb8ff14d1c6ce3","user":{"login":"convoyinc","id":11140206,"avatar_url":"https://avatars.githubusercontent.com/u/11140206?v=3","gravatar_id":"","url":"https://api.github.com/users/convoyinc","html_url":"https://github.com/convoyinc","followers_url":"https://api.github.com/users/convoyinc/followers","following_url":"https://api.github.com/users/convoyinc/following{/other_user}","gists_url":"https://api.github.com/users/convoyinc/gists{/gist_id}","starred_url":"https://api.github.com/users/convoyinc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/convoyinc/subscriptions","organizations_url":"https://api.github.com/users/convoyinc/orgs","repos_url":"https://api.github.com/users/convoyinc/repos","events_url":"https://api.github.com/users/convoyinc/events{/privacy}","received_events_url":"https://api.github.com/users/convoyinc/received_events","type":"Organization","site_admin":false},"repo":{"id":68745114,"name":"sequelize","full_name":"convoyinc/sequelize","owner":{"login":"convoyinc","id":11140206,"avatar_url":"https://avatars.githubusercontent.com/u/11140206?v=3","gravatar_id":"","url":"https://api.github.com/users/convoyinc","html_url":"https://github.com/convoyinc","followers_url":"https://api.github.com/users/convoyinc/followers","following_url":"https://api.github.com/users/convoyinc/following{/other_user}","gists_url":"https://api.github.com/users/convoyinc/gists{/gist_id}","starred_url":"https://api.github.com/users/convoyinc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/convoyinc/subscriptions","organizations_url":"https://api.github.com/users/convoyinc/orgs","repos_url":"https://api.github.com/users/convoyinc/repos","events_url":"https://api.github.com/users/convoyinc/events{/privacy}","received_events_url":"https://api.github.com/users/convoyinc/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/convoyinc/sequelize","description":"An easy-to-use multi SQL dialect ORM for Node.js","fork":true,"url":"https://api.github.com/repos/convoyinc/sequelize","forks_url":"https://api.github.com/repos/convoyinc/sequelize/forks","keys_url":"https://api.github.com/repos/convoyinc/sequelize/keys{/key_id}","collaborators_url":"https://api.github.com/repos/convoyinc/sequelize/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/convoyinc/sequelize/teams","hooks_url":"https://api.github.com/repos/convoyinc/sequelize/hooks","issue_events_url":"https://api.github.com/repos/convoyinc/sequelize/issues/events{/number}","events_url":"https://api.github.com/repos/convoyinc/sequelize/events","assignees_url":"https://api.github.com/repos/convoyinc/sequelize/assignees{/user}","branches_url":"https://api.github.com/repos/convoyinc/sequelize/branches{/branch}","tags_url":"https://api.github.com/repos/convoyinc/sequelize/tags","blobs_url":"https://api.github.com/repos/convoyinc/sequelize/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/convoyinc/sequelize/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/convoyinc/sequelize/git/refs{/sha}","trees_url":"https://api.github.com/repos/convoyinc/sequelize/git/trees{/sha}","statuses_url":"https://api.github.com/repos/convoyinc/sequelize/statuses/{sha}","languages_url":"https://api.github.com/repos/convoyinc/sequelize/languages","stargazers_url":"https://api.github.com/repos/convoyinc/sequelize/stargazers","contributors_url":"https://api.github.com/repos/convoyinc/sequelize/contributors","subscribers_url":"https://api.github.com/repos/convoyinc/sequelize/subscribers","subscription_url":"https://api.github.com/repos/convoyinc/sequelize/subscription","commits_url":"https://api.github.com/repos/convoyinc/sequelize/commits{/sha}","git_commits_url":"https://api.github.com/repos/convoyinc/sequelize/git/commits{/sha}","comments_url":"https://api.github.com/repos/convoyinc/sequelize/comments{/number}","issue_comment_url":"https://api.github.com/repos/convoyinc/sequelize/issues/comments{/number}","contents_url":"https://api.github.com/repos/convoyinc/sequelize/contents/{+path}","compare_url":"https://api.github.com/repos/convoyinc/sequelize/compare/{base}...{head}","merges_url":"https://api.github.com/repos/convoyinc/sequelize/merges","archive_url":"https://api.github.com/repos/convoyinc/sequelize/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/convoyinc/sequelize/downloads","issues_url":"https://api.github.com/repos/convoyinc/sequelize/issues{/number}","pulls_url":"https://api.github.com/repos/convoyinc/sequelize/pulls{/number}","milestones_url":"https://api.github.com/repos/convoyinc/sequelize/milestones{/number}","notifications_url":"https://api.github.com/repos/convoyinc/sequelize/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/convoyinc/sequelize/labels{/name}","releases_url":"https://api.github.com/repos/convoyinc/sequelize/releases{/id}","deployments_url":"https://api.github.com/repos/convoyinc/sequelize/deployments","created_at":"2016-09-20T19:16:21Z","updated_at":"2016-09-20T19:16:28Z","pushed_at":"2016-10-13T23:46:44Z","git_url":"git://github.com/convoyinc/sequelize.git","ssh_url":"git@github.com:convoyinc/sequelize.git","clone_url":"https://github.com/convoyinc/sequelize.git","svn_url":"https://github.com/convoyinc/sequelize","homepage":"http://sequelizejs.com","size":18860,"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":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"sequelize:master","ref":"master","sha":"e608bb293582f7e2b17dd7901fb1ee96c4fdcb09","user":{"login":"sequelize","id":3591786,"avatar_url":"https://avatars.githubusercontent.com/u/3591786?v=3","gravatar_id":"","url":"https://api.github.com/users/sequelize","html_url":"https://github.com/sequelize","followers_url":"https://api.github.com/users/sequelize/followers","following_url":"https://api.github.com/users/sequelize/following{/other_user}","gists_url":"https://api.github.com/users/sequelize/gists{/gist_id}","starred_url":"https://api.github.com/users/sequelize/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sequelize/subscriptions","organizations_url":"https://api.github.com/users/sequelize/orgs","repos_url":"https://api.github.com/users/sequelize/repos","events_url":"https://api.github.com/users/sequelize/events{/privacy}","received_events_url":"https://api.github.com/users/sequelize/received_events","type":"Organization","site_admin":false},"repo":{"id":790359,"name":"sequelize","full_name":"sequelize/sequelize","owner":{"login":"sequelize","id":3591786,"avatar_url":"https://avatars.githubusercontent.com/u/3591786?v=3","gravatar_id":"","url":"https://api.github.com/users/sequelize","html_url":"https://github.com/sequelize","followers_url":"https://api.github.com/users/sequelize/followers","following_url":"https://api.github.com/users/sequelize/following{/other_user}","gists_url":"https://api.github.com/users/sequelize/gists{/gist_id}","starred_url":"https://api.github.com/users/sequelize/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sequelize/subscriptions","organizations_url":"https://api.github.com/users/sequelize/orgs","repos_url":"https://api.github.com/users/sequelize/repos","events_url":"https://api.github.com/users/sequelize/events{/privacy}","received_events_url":"https://api.github.com/users/sequelize/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/sequelize/sequelize","description":"An easy-to-use multi SQL dialect ORM for Node.js","fork":false,"url":"https://api.github.com/repos/sequelize/sequelize","forks_url":"https://api.github.com/repos/sequelize/sequelize/forks","keys_url":"https://api.github.com/repos/sequelize/sequelize/keys{/key_id}","collaborators_url":"https://api.github.com/repos/sequelize/sequelize/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/sequelize/sequelize/teams","hooks_url":"https://api.github.com/repos/sequelize/sequelize/hooks","issue_events_url":"https://api.github.com/repos/sequelize/sequelize/issues/events{/number}","events_url":"https://api.github.com/repos/sequelize/sequelize/events","assignees_url":"https://api.github.com/repos/sequelize/sequelize/assignees{/user}","branches_url":"https://api.github.com/repos/sequelize/sequelize/branches{/branch}","tags_url":"https://api.github.com/repos/sequelize/sequelize/tags","blobs_url":"https://api.github.com/repos/sequelize/sequelize/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/sequelize/sequelize/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/sequelize/sequelize/git/refs{/sha}","trees_url":"https://api.github.com/repos/sequelize/sequelize/git/trees{/sha}","statuses_url":"https://api.github.com/repos/sequelize/sequelize/statuses/{sha}","languages_url":"https://api.github.com/repos/sequelize/sequelize/languages","stargazers_url":"https://api.github.com/repos/sequelize/sequelize/stargazers","contributors_url":"https://api.github.com/repos/sequelize/sequelize/contributors","subscribers_url":"https://api.github.com/repos/sequelize/sequelize/subscribers","subscription_url":"https://api.github.com/repos/sequelize/sequelize/subscription","commits_url":"https://api.github.com/repos/sequelize/sequelize/commits{/sha}","git_commits_url":"https://api.github.com/repos/sequelize/sequelize/git/commits{/sha}","comments_url":"https://api.github.com/repos/sequelize/sequelize/comments{/number}","issue_comment_url":"https://api.github.com/repos/sequelize/sequelize/issues/comments{/number}","contents_url":"https://api.github.com/repos/sequelize/sequelize/contents/{+path}","compare_url":"https://api.github.com/repos/sequelize/sequelize/compare/{base}...{head}","merges_url":"https://api.github.com/repos/sequelize/sequelize/merges","archive_url":"https://api.github.com/repos/sequelize/sequelize/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/sequelize/sequelize/downloads","issues_url":"https://api.github.com/repos/sequelize/sequelize/issues{/number}","pulls_url":"https://api.github.com/repos/sequelize/sequelize/pulls{/number}","milestones_url":"https://api.github.com/repos/sequelize/sequelize/milestones{/number}","notifications_url":"https://api.github.com/repos/sequelize/sequelize/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/sequelize/sequelize/labels{/name}","releases_url":"https://api.github.com/repos/sequelize/sequelize/releases{/id}","deployments_url":"https://api.github.com/repos/sequelize/sequelize/deployments","created_at":"2010-07-22T07:11:11Z","updated_at":"2016-10-13T23:15:31Z","pushed_at":"2016-10-13T23:46:46Z","git_url":"git://github.com/sequelize/sequelize.git","ssh_url":"git@github.com:sequelize/sequelize.git","clone_url":"https://github.com/sequelize/sequelize.git","svn_url":"https://github.com/sequelize/sequelize","homepage":"http://sequelizejs.com","size":56236,"stargazers_count":7732,"watchers_count":7732,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1562,"mirror_url":null,"open_issues_count":745,"forks":1562,"open_issues":745,"watchers":7732,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/sequelize/sequelize/pulls/6637"},"html":{"href":"https://github.com/sequelize/sequelize/pull/6637"},"issue":{"href":"https://api.github.com/repos/sequelize/sequelize/issues/6637"},"comments":{"href":"https://api.github.com/repos/sequelize/sequelize/issues/6637/comments"},"review_comments":{"href":"https://api.github.com/repos/sequelize/sequelize/pulls/6637/comments"},"review_comment":{"href":"https://api.github.com/repos/sequelize/sequelize/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/sequelize/sequelize/pulls/6637/commits"},"statuses":{"href":"https://api.github.com/repos/sequelize/sequelize/statuses/b37fcf1d2368c5f0c1db908b0ddb8ff14d1c6ce3"}}}}
{"actor":{"display_login":"SimonSchick"}}