{"action":"created","comment":{"url":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/comments/26483542","id":26483542,"diff_hunk":"@@ -928,119 +757,269 @@\n     [\"SELECT id from factsets WHERE certname = ?\" certname]\n     (:id (first result-set))))\n \n-(pls/defn-validated factset-map :- {s/Str s/Str}\n-  \"Return all facts and their values for a given certname as a map\"\n+(defn-validated delete-pending-path-id-orphans!\n+  \"Delete paths in removed-pid-vid-pairs that are no longer mentioned\n+  in facts.\"\n+  [factset-id removed-pid-vid-pairs]\n+  (when-let [removed-pid-vid-pairs (seq removed-pid-vid-pairs)]\n+    (let [pids (map first removed-pid-vid-pairs)\n+          fv-id-pairs (map vector\n+                           (repeat factset-id )\n+                           (map second removed-pid-vid-pairs))\n+          in-pids (jdbc/in-clause pids)\n+          in-fv-id-pairs (jdbc/in-clause-multi fv-id-pairs 2)]\n+      (sql/do-prepared\n+       (format\n+        \"DELETE FROM fact_paths fp\n+           WHERE fp.id %s\n+             AND NOT EXISTS (SELECT 1 FROM facts f\n+                               WHERE f.fact_path_id %s\n+                                 AND f.fact_path_id = fp.id\n+                                 AND (f.factset_id, f.fact_value_id) NOT %s)\"\n+        in-pids in-pids in-fv-id-pairs)\n+       (flatten [pids pids fv-id-pairs])))))\n+\n+(defn-validated delete-pending-value-id-orphans!\n+  \"Delete values in removed-pid-vid-pairs that are no longer mentioned\n+  in facts.\"\n+  [factset-id removed-pid-vid-pairs]\n+  (when-let [removed-pid-vid-pairs (seq removed-pid-vid-pairs)]\n+    (let [vids (map second removed-pid-vid-pairs)\n+          fp-id-pairs (map vector\n+                           (repeat factset-id )\n+                           (map first removed-pid-vid-pairs))\n+          in-vids (jdbc/in-clause vids)\n+          in-fp-id-pairs (jdbc/in-clause-multi fp-id-pairs 2)]\n+      (sql/do-prepared\n+       (format\n+        \"DELETE FROM fact_values fv\n+           WHERE fv.id %s\n+             AND NOT EXISTS (SELECT 1 FROM facts f\n+                               WHERE f.fact_value_id %s\n+                                 AND f.fact_value_id = fv.id\n+                                 AND (f.factset_id, f.fact_path_id) NOT %s)\"\n+        in-vids in-vids in-fp-id-pairs)\n+       (flatten [vids vids fp-id-pairs])))))\n+\n+(defn-validated delete-orphaned-paths! :- s/Int\n+  \"Deletes up to n paths that are no longer mentioned by any factsets,\n+  and returns the number actually deleted.  These orphans can be\n+  created by races between parallel updates since (for performance) we\n+  don't serialize those transactions.  Via repeatable read, an update\n+  transaction may decide not to delete paths that are only referred to\n+  by other facts that are being changed in parallel transactions to\n+  also not refer to the paths.\"\n+  [n :- (s/both s/Int (s/pred (complement neg?) 'nonnegative?))]\n+  (if (zero? n)\n+    0\n+    (first\n+     (sql/transaction\n+      (sql/do-prepared\n+       \"DELETE FROM fact_paths\n+          WHERE id IN (SELECT fp.id\n+                         FROM fact_paths fp\n+                         WHERE NOT EXISTS (SELECT 1\n+                                             FROM facts f\n+                                             WHERE fp.id = f.fact_path_id)\n+                         LIMIT ?)\"\n+       [n])))))\n+\n+(defn-validated delete-orphaned-values! :- s/Int\n+  \"Deletes up to n values that are no longer mentioned by any\n+  factsets, and returns the number actually deleted.  These orphans\n+  can be created by races between parallel updates since (for\n+  performance) we don't serialize those transactions.  Via repeatable\n+  read, an update transaction may decide not to delete values that are\n+  only referred to by other facts that are being changed in parallel\n+  transactions to also not refer to the values.\"\n+  [n :- (s/both s/Int (s/pred (complement neg?) 'nonnegative?))]\n+  (if (zero? n)\n+    0\n+    (first\n+     (sql/transaction\n+      (sql/do-prepared\n+       \"DELETE FROM fact_values\n+          WHERE id in (SELECT fv.id\n+                         FROM fact_values fv\n+                         WHERE NOT EXISTS (SELECT 1\n+                                             FROM facts f\n+                                             WHERE fv.id = f.fact_value_id)\n+                         LIMIT ?)\"\n+       [n])))))\n+\n+;; NOTE: now only used in tests.\n+(defn-validated delete-certname-facts!\n+  \"Delete all the facts for certname.\"\n   [certname :- String]\n-  (sql/with-query-results result-set\n-    [\"SELECT fp.path as name,\n-             COALESCE(fv.value_string,\n-                      cast(fv.value_integer as text),\n-                      cast(fv.value_boolean as text),\n-                      cast(fv.value_float as text),\n-                      '') as value\n-             FROM factsets fs\n-                  INNER JOIN facts as f on fs.id = f.factset_id\n-                  INNER JOIN fact_values as fv on f.fact_value_id = fv.id\n-                  INNER JOIN fact_paths as fp on fv.path_id = fp.id\n-             WHERE fp.depth = 0 AND\n-                   fs.certname = ?\"\n-     certname]\n-    (zipmap (map :name result-set)\n-            (map :value result-set))))\n-\n-(pls/defn-validated insert-facts!\n-  \"Given a certname and set of fact_value_id's, insert them into the facts table\"\n-  [factset :- s/Int\n-   ids     :- #{s/Int}]\n-  (let [default {:factset_id factset}\n-        rows    (map #(assoc default :fact_value_id %)\n-                     ids)]\n-    (apply sql/insert-records :facts rows)))\n+  (sql/transaction\n+   (let [factset-id (certname-to-factset-id certname)\n+         dead-pairs (select-pid-vid-pairs-for-factset factset-id)]\n+     (sql/do-commands\n+      (format \"DELETE FROM facts WHERE factset_id = %s\" factset-id))\n+     (delete-pending-path-id-orphans! factset-id dead-pairs)\n+     (delete-pending-value-id-orphans! factset-id dead-pairs)\n+     (sql/delete-rows :factsets [\"id=?\" factset-id]))))\n+\n+(defn-validated insert-facts-pv-pairs!\n+  [factset-id :- s/Int\n+   pairs :- (s/either [(s/pair s/Int \"path-id\" s/Int \"value-id\")]\n+                      #{(s/pair s/Int \"path-id\" s/Int \"value-id\")})]\n+  (apply sql/insert-records\n+         :facts\n+         (for [[pid vid] pairs]\n+           {:factset_id factset-id :fact_path_id pid :fact_value_id vid})))\n+\n+(defn existing-paths->ids\n+  \"Returns a map from path strings to id for each path that's already\n+  in the database.\"\n+  [pathstrs]\n+  (into {}\n+        (for [{:keys [path id]}\n+              (apply query-to-vec\n+                     (format \"select path, id from fact_paths where path %s\"\n+                             (jdbc/in-clause pathstrs))\n+                     pathstrs)]\n+          [path id])))\n+\n+(defn insert-new-paths!\n+  \"Inserts the path strings into the database and returns a map from\n+  the path strings to their database ids.\"\n+  [pathstrs]\n+  (zipmap pathstrs\n+          (map :id (apply\n+                    sql/insert-records :fact_paths\n+                    (map (comp facts/path->pathmap facts/string-to-factpath)\n+                         pathstrs)))))\n+\n+(defn existing-value-hashes->ids\n+  \"Returns a map from value hash to id for each value that's already\n+  in the database.\"\n+  [value-hashes]\n+  (into {}\n+        (for [{:keys [value_hash id]}\n+              (apply query-to-vec\n+                     (format \"SELECT value_hash, id FROM fact_values\n+                                WHERE value_hash %s\"\n+                             (jdbc/in-clause value-hashes))\n+                     value-hashes)]\n+          [value_hash id])))\n+\n+(defn insert-new-values!\n+  \"Inserts the valuemaps into the database and returns a map from\n+  value hash to valuemap.  The returned valuemaps will have an :id.\"\n+  [valuemaps]\n+  (let [vhashes (map :value_hash valuemaps)]\n+    (zipmap vhashes\n+            (let [vmaps valuemaps]","path":"src/com/puppetlabs/puppetdb/scf/storage.clj","position":424,"original_position":424,"commit_id":"5e22d9b0cefbe10b2990b4ff4bc113faeb4afc59","original_commit_id":"5e22d9b0cefbe10b2990b4ff4bc113faeb4afc59","user":{"login":"senior","id":215910,"avatar_url":"https://avatars.githubusercontent.com/u/215910?v=3","gravatar_id":"","url":"https://api.github.com/users/senior","html_url":"https://github.com/senior","followers_url":"https://api.github.com/users/senior/followers","following_url":"https://api.github.com/users/senior/following{/other_user}","gists_url":"https://api.github.com/users/senior/gists{/gist_id}","starred_url":"https://api.github.com/users/senior/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/senior/subscriptions","organizations_url":"https://api.github.com/users/senior/orgs","repos_url":"https://api.github.com/users/senior/repos","events_url":"https://api.github.com/users/senior/events{/privacy}","received_events_url":"https://api.github.com/users/senior/received_events","type":"User","site_admin":false},"body":"why let bind to vmaps here?","created_at":"2015-03-16T13:30:25Z","updated_at":"2015-03-16T13:30:25Z","html_url":"https://github.com/puppetlabs/puppetdb/pull/1296#discussion_r26483542","pull_request_url":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1296","_links":{"self":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/comments/26483542"},"html":{"href":"https://github.com/puppetlabs/puppetdb/pull/1296#discussion_r26483542"},"pull_request":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1296"}}},"pull_request":{"url":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1296","id":30971487,"html_url":"https://github.com/puppetlabs/puppetdb/pull/1296","diff_url":"https://github.com/puppetlabs/puppetdb/pull/1296.diff","patch_url":"https://github.com/puppetlabs/puppetdb/pull/1296.patch","issue_url":"https://api.github.com/repos/puppetlabs/puppetdb/issues/1296","number":1296,"state":"open","locked":false,"title":"(PDB-1226) Lift fact paths into facts (also PDB-1224, PDB-1225) [WIP]","user":{"login":"rbrw","id":10120698,"avatar_url":"https://avatars.githubusercontent.com/u/10120698?v=3","gravatar_id":"","url":"https://api.github.com/users/rbrw","html_url":"https://github.com/rbrw","followers_url":"https://api.github.com/users/rbrw/followers","following_url":"https://api.github.com/users/rbrw/following{/other_user}","gists_url":"https://api.github.com/users/rbrw/gists{/gist_id}","starred_url":"https://api.github.com/users/rbrw/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rbrw/subscriptions","organizations_url":"https://api.github.com/users/rbrw/orgs","repos_url":"https://api.github.com/users/rbrw/repos","events_url":"https://api.github.com/users/rbrw/events{/privacy}","received_events_url":"https://api.github.com/users/rbrw/received_events","type":"User","site_admin":false},"body":"This series migrates the database to use the new facts structure:\r\n\r\n(factset_id fact_path_id fact_value_id)\r\n\r\nand changes the code to accommodate that. When reviewing, it may be easier to look at the changes to storage.clj and facts.clj directly, as compared to the diff. Or, if we like, I can probably take some time to break up the PDB-1225 patch into more easily digested pieces.\r\n\r\nThere are still a few FIXMEs (questions) to consider, but nothing significant (that I know of).\r\n\r\nRob Browning (3):\r\n  (PDB-1224) Move paths from values to facts\r\n  (PDB-1225) Accommodate move of fact paths to facts [WIP]\r\n  (PDB-1226) Add global incremental fact/path GC\r\n\r\nRyan Senior (1):\r\n  Update query engine, v3 endpoints for fact_path move\r\n\r\n documentation/repl.markdown                        |   3 +-\r\n src/com/puppetlabs/puppetdb/cli/services.clj       |   3 +-\r\n src/com/puppetlabs/puppetdb/facts.clj              |  84 +--\r\n src/com/puppetlabs/puppetdb/query.clj              |   8 +-\r\n src/com/puppetlabs/puppetdb/query/facts.clj        |   2 +-\r\n src/com/puppetlabs/puppetdb/query_eng.clj          |  21 +-\r\n src/com/puppetlabs/puppetdb/scf/migrate.clj        | 109 +++-\r\n .../puppetlabs/puppetdb/scf/migration_legacy.clj   | 279 ++++++++++\r\n src/com/puppetlabs/puppetdb/scf/storage.clj        | 577 ++++++++++-----------\r\n test/com/puppetlabs/puppetdb/test/command.clj      |  10 +-\r\n test/com/puppetlabs/puppetdb/test/facts.clj        |  72 ---\r\n .../puppetdb/test/scf/migration_legacy.clj         |  76 +++\r\n test/com/puppetlabs/puppetdb/test/scf/storage.clj  | 161 +++++-\r\n 13 files changed, 961 insertions(+), 444 deletions(-)\r\n create mode 100644 src/com/puppetlabs/puppetdb/scf/migration_legacy.clj\r\n create mode 100644 test/com/puppetlabs/puppetdb/test/scf/migration_legacy.clj\r\n\r\nCloses: PDB-1224 PDB-1225 PDB-1226\r\n","created_at":"2015-03-11T18:29:24Z","updated_at":"2015-03-16T13:30:25Z","closed_at":null,"merged_at":null,"merge_commit_sha":"afdcb47e3afd99e9d329bb68ee1ac9bf6e691e19","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1296/commits","review_comments_url":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1296/comments","review_comment_url":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/comments{/number}","comments_url":"https://api.github.com/repos/puppetlabs/puppetdb/issues/1296/comments","statuses_url":"https://api.github.com/repos/puppetlabs/puppetdb/statuses/5e22d9b0cefbe10b2990b4ff4bc113faeb4afc59","head":{"label":"rbrw:ticket/stable/pdb-1226-global-inc-gc","ref":"ticket/stable/pdb-1226-global-inc-gc","sha":"5e22d9b0cefbe10b2990b4ff4bc113faeb4afc59","user":{"login":"rbrw","id":10120698,"avatar_url":"https://avatars.githubusercontent.com/u/10120698?v=3","gravatar_id":"","url":"https://api.github.com/users/rbrw","html_url":"https://github.com/rbrw","followers_url":"https://api.github.com/users/rbrw/followers","following_url":"https://api.github.com/users/rbrw/following{/other_user}","gists_url":"https://api.github.com/users/rbrw/gists{/gist_id}","starred_url":"https://api.github.com/users/rbrw/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rbrw/subscriptions","organizations_url":"https://api.github.com/users/rbrw/orgs","repos_url":"https://api.github.com/users/rbrw/repos","events_url":"https://api.github.com/users/rbrw/events{/privacy}","received_events_url":"https://api.github.com/users/rbrw/received_events","type":"User","site_admin":false},"repo":{"id":27739513,"name":"puppetdb","full_name":"rbrw/puppetdb","owner":{"login":"rbrw","id":10120698,"avatar_url":"https://avatars.githubusercontent.com/u/10120698?v=3","gravatar_id":"","url":"https://api.github.com/users/rbrw","html_url":"https://github.com/rbrw","followers_url":"https://api.github.com/users/rbrw/followers","following_url":"https://api.github.com/users/rbrw/following{/other_user}","gists_url":"https://api.github.com/users/rbrw/gists{/gist_id}","starred_url":"https://api.github.com/users/rbrw/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rbrw/subscriptions","organizations_url":"https://api.github.com/users/rbrw/orgs","repos_url":"https://api.github.com/users/rbrw/repos","events_url":"https://api.github.com/users/rbrw/events{/privacy}","received_events_url":"https://api.github.com/users/rbrw/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/rbrw/puppetdb","description":"Centralized Puppet Storage","fork":true,"url":"https://api.github.com/repos/rbrw/puppetdb","forks_url":"https://api.github.com/repos/rbrw/puppetdb/forks","keys_url":"https://api.github.com/repos/rbrw/puppetdb/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rbrw/puppetdb/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rbrw/puppetdb/teams","hooks_url":"https://api.github.com/repos/rbrw/puppetdb/hooks","issue_events_url":"https://api.github.com/repos/rbrw/puppetdb/issues/events{/number}","events_url":"https://api.github.com/repos/rbrw/puppetdb/events","assignees_url":"https://api.github.com/repos/rbrw/puppetdb/assignees{/user}","branches_url":"https://api.github.com/repos/rbrw/puppetdb/branches{/branch}","tags_url":"https://api.github.com/repos/rbrw/puppetdb/tags","blobs_url":"https://api.github.com/repos/rbrw/puppetdb/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rbrw/puppetdb/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rbrw/puppetdb/git/refs{/sha}","trees_url":"https://api.github.com/repos/rbrw/puppetdb/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rbrw/puppetdb/statuses/{sha}","languages_url":"https://api.github.com/repos/rbrw/puppetdb/languages","stargazers_url":"https://api.github.com/repos/rbrw/puppetdb/stargazers","contributors_url":"https://api.github.com/repos/rbrw/puppetdb/contributors","subscribers_url":"https://api.github.com/repos/rbrw/puppetdb/subscribers","subscription_url":"https://api.github.com/repos/rbrw/puppetdb/subscription","commits_url":"https://api.github.com/repos/rbrw/puppetdb/commits{/sha}","git_commits_url":"https://api.github.com/repos/rbrw/puppetdb/git/commits{/sha}","comments_url":"https://api.github.com/repos/rbrw/puppetdb/comments{/number}","issue_comment_url":"https://api.github.com/repos/rbrw/puppetdb/issues/comments{/number}","contents_url":"https://api.github.com/repos/rbrw/puppetdb/contents/{+path}","compare_url":"https://api.github.com/repos/rbrw/puppetdb/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rbrw/puppetdb/merges","archive_url":"https://api.github.com/repos/rbrw/puppetdb/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rbrw/puppetdb/downloads","issues_url":"https://api.github.com/repos/rbrw/puppetdb/issues{/number}","pulls_url":"https://api.github.com/repos/rbrw/puppetdb/pulls{/number}","milestones_url":"https://api.github.com/repos/rbrw/puppetdb/milestones{/number}","notifications_url":"https://api.github.com/repos/rbrw/puppetdb/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rbrw/puppetdb/labels{/name}","releases_url":"https://api.github.com/repos/rbrw/puppetdb/releases{/id}","created_at":"2014-12-08T23:03:46Z","updated_at":"2014-12-08T23:03:47Z","pushed_at":"2015-03-13T18:58:22Z","git_url":"git://github.com/rbrw/puppetdb.git","ssh_url":"git@github.com:rbrw/puppetdb.git","clone_url":"https://github.com/rbrw/puppetdb.git","svn_url":"https://github.com/rbrw/puppetdb","homepage":"http://docs.puppetlabs.com/puppetdb","size":12028,"stargazers_count":0,"watchers_count":0,"language":"Clojure","has_issues":false,"has_downloads":true,"has_wiki":false,"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":"puppetlabs:stable","ref":"stable","sha":"71646c6d05547147faf87a3382c6fac75a07f0cd","user":{"login":"puppetlabs","id":234268,"avatar_url":"https://avatars.githubusercontent.com/u/234268?v=3","gravatar_id":"","url":"https://api.github.com/users/puppetlabs","html_url":"https://github.com/puppetlabs","followers_url":"https://api.github.com/users/puppetlabs/followers","following_url":"https://api.github.com/users/puppetlabs/following{/other_user}","gists_url":"https://api.github.com/users/puppetlabs/gists{/gist_id}","starred_url":"https://api.github.com/users/puppetlabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/puppetlabs/subscriptions","organizations_url":"https://api.github.com/users/puppetlabs/orgs","repos_url":"https://api.github.com/users/puppetlabs/repos","events_url":"https://api.github.com/users/puppetlabs/events{/privacy}","received_events_url":"https://api.github.com/users/puppetlabs/received_events","type":"Organization","site_admin":false},"repo":{"id":2193032,"name":"puppetdb","full_name":"puppetlabs/puppetdb","owner":{"login":"puppetlabs","id":234268,"avatar_url":"https://avatars.githubusercontent.com/u/234268?v=3","gravatar_id":"","url":"https://api.github.com/users/puppetlabs","html_url":"https://github.com/puppetlabs","followers_url":"https://api.github.com/users/puppetlabs/followers","following_url":"https://api.github.com/users/puppetlabs/following{/other_user}","gists_url":"https://api.github.com/users/puppetlabs/gists{/gist_id}","starred_url":"https://api.github.com/users/puppetlabs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/puppetlabs/subscriptions","organizations_url":"https://api.github.com/users/puppetlabs/orgs","repos_url":"https://api.github.com/users/puppetlabs/repos","events_url":"https://api.github.com/users/puppetlabs/events{/privacy}","received_events_url":"https://api.github.com/users/puppetlabs/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/puppetlabs/puppetdb","description":"Centralized Puppet Storage","fork":false,"url":"https://api.github.com/repos/puppetlabs/puppetdb","forks_url":"https://api.github.com/repos/puppetlabs/puppetdb/forks","keys_url":"https://api.github.com/repos/puppetlabs/puppetdb/keys{/key_id}","collaborators_url":"https://api.github.com/repos/puppetlabs/puppetdb/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/puppetlabs/puppetdb/teams","hooks_url":"https://api.github.com/repos/puppetlabs/puppetdb/hooks","issue_events_url":"https://api.github.com/repos/puppetlabs/puppetdb/issues/events{/number}","events_url":"https://api.github.com/repos/puppetlabs/puppetdb/events","assignees_url":"https://api.github.com/repos/puppetlabs/puppetdb/assignees{/user}","branches_url":"https://api.github.com/repos/puppetlabs/puppetdb/branches{/branch}","tags_url":"https://api.github.com/repos/puppetlabs/puppetdb/tags","blobs_url":"https://api.github.com/repos/puppetlabs/puppetdb/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/puppetlabs/puppetdb/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/puppetlabs/puppetdb/git/refs{/sha}","trees_url":"https://api.github.com/repos/puppetlabs/puppetdb/git/trees{/sha}","statuses_url":"https://api.github.com/repos/puppetlabs/puppetdb/statuses/{sha}","languages_url":"https://api.github.com/repos/puppetlabs/puppetdb/languages","stargazers_url":"https://api.github.com/repos/puppetlabs/puppetdb/stargazers","contributors_url":"https://api.github.com/repos/puppetlabs/puppetdb/contributors","subscribers_url":"https://api.github.com/repos/puppetlabs/puppetdb/subscribers","subscription_url":"https://api.github.com/repos/puppetlabs/puppetdb/subscription","commits_url":"https://api.github.com/repos/puppetlabs/puppetdb/commits{/sha}","git_commits_url":"https://api.github.com/repos/puppetlabs/puppetdb/git/commits{/sha}","comments_url":"https://api.github.com/repos/puppetlabs/puppetdb/comments{/number}","issue_comment_url":"https://api.github.com/repos/puppetlabs/puppetdb/issues/comments{/number}","contents_url":"https://api.github.com/repos/puppetlabs/puppetdb/contents/{+path}","compare_url":"https://api.github.com/repos/puppetlabs/puppetdb/compare/{base}...{head}","merges_url":"https://api.github.com/repos/puppetlabs/puppetdb/merges","archive_url":"https://api.github.com/repos/puppetlabs/puppetdb/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/puppetlabs/puppetdb/downloads","issues_url":"https://api.github.com/repos/puppetlabs/puppetdb/issues{/number}","pulls_url":"https://api.github.com/repos/puppetlabs/puppetdb/pulls{/number}","milestones_url":"https://api.github.com/repos/puppetlabs/puppetdb/milestones{/number}","notifications_url":"https://api.github.com/repos/puppetlabs/puppetdb/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/puppetlabs/puppetdb/labels{/name}","releases_url":"https://api.github.com/repos/puppetlabs/puppetdb/releases{/id}","created_at":"2011-08-11T18:54:46Z","updated_at":"2015-03-15T06:03:23Z","pushed_at":"2015-03-13T21:07:53Z","git_url":"git://github.com/puppetlabs/puppetdb.git","ssh_url":"git@github.com:puppetlabs/puppetdb.git","clone_url":"https://github.com/puppetlabs/puppetdb.git","svn_url":"https://github.com/puppetlabs/puppetdb","homepage":"http://docs.puppetlabs.com/puppetdb","size":18910,"stargazers_count":153,"watchers_count":153,"language":"Clojure","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":126,"mirror_url":null,"open_issues_count":9,"forks":126,"open_issues":9,"watchers":153,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1296"},"html":{"href":"https://github.com/puppetlabs/puppetdb/pull/1296"},"issue":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/issues/1296"},"comments":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/issues/1296/comments"},"review_comments":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1296/comments"},"review_comment":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/pulls/1296/commits"},"statuses":{"href":"https://api.github.com/repos/puppetlabs/puppetdb/statuses/5e22d9b0cefbe10b2990b4ff4bc113faeb4afc59"}}}}