{"action":"created","comment":{"url":"https://api.github.com/repos/danpaz/bodybuilder/pulls/comments/85070284","pull_request_review_id":5806303,"id":85070284,"diff_hunk":"@@ -0,0 +1,186 @@\n+import _ from 'lodash'\n+import {boolMerge} from './utils'\n+\n+/**\n+ * QueryBuilder class to build query clauses.\n+ *\n+ * @private\n+ */\n+export default class QueryBuilder {\n+\n+  constructor() {\n+    this._queries = {}\n+    this._filters = {}\n+    this._aggs = {}\n+  }\n+\n+  get queries() {\n+    return _.cloneDeep(this._queries)\n+  }\n+\n+  /**\n+   * Apply a query of a given type providing all the necessary arguments,\n+   * passing these arguments directly to the specified query builder. Merges\n+   * existing query(s) with the new query.\n+   *\n+   * @param  {String}  boolType Name of the query type.\n+   * @param  {...args} args     Arguments passed to query builder.\n+   * @returns {QueryBuilder}    Builder class.\n+   */\n+  _makeQuery(boolType, ...args) {\n+    let nested = _.last(args)\n+\n+    let newQuery = this._buildQuery(...args)\n+\n+    if (_.isFunction(nested)) {\n+      let clause = newQuery[_.findKey(newQuery)]\n+      let builder = new QueryBuilder()\n+      let recursiveResult = nested(builder)\n+      if (!_.isEmpty(recursiveResult._aggs)) {clause.aggs = recursiveResult._aggs}\n+      if (!_.isEmpty(recursiveResult._queries)) {clause.query = recursiveResult._queries}\n+      if (!_.isEmpty(recursiveResult._filters)) {clause.filter = recursiveResult._filters}\n+\n+      return newQuery\n+    }\n+\n+    return boolMerge(newQuery, this._queries, boolType)\n+  }\n+\n+  _buildQuery(type, field, value, opts) {\n+    let clause = {}\n+\n+    if (field && value && opts) {\n+      clause = _.merge({[field]: value}, opts)\n+    } else if (field && value) {\n+      clause = {[field]: value}\n+    } else if (field) {\n+      clause = {field}\n+    }\n+\n+    return {[type]: clause}\n+  }\n+\n+  _makeFilter(boolType, ...args) {\n+    let nested = _.last(args)\n+\n+    let newFilter = this._buildFilter(...args)\n+\n+    if (_.isFunction(nested)) {\n+      let clause = newFilter[_.findKey(newFilter)]\n+      let builder = new QueryBuilder()\n+      let recursiveResult = nested(builder)\n+\n+      if (!_.isEmpty(recursiveResult._aggs)) {clause.aggs = recursiveResult._aggs}\n+      if (!_.isEmpty(recursiveResult._queries)) {clause.query = recursiveResult._queries}\n+      if (!_.isEmpty(recursiveResult._filters)) {clause.filter = recursiveResult._filters}\n+\n+      return newFilter\n+    }\n+\n+    return boolMerge(newFilter, this._filters, boolType)\n+  }\n+\n+  _buildFilter(type, field, value, opts) {\n+    let clause = {}\n+\n+    if (field && value && opts) {\n+      clause = _.merge({[field]: value}, opts)\n+    } else if (field && value) {\n+      clause = {[field]: value}\n+    } else if (field) {\n+      clause = {field}\n+    }\n+\n+    return {[type]: clause}\n+  }\n+\n+  _makeAggregation(...args) {\n+    let nested = _.last(args)\n+\n+    let newAggregation = this._buildAggregation(...args)\n+\n+    if (_.isFunction(nested)) {\n+      let clause = newAggregation[_.findKey(newAggregation)]","path":"src/query-builder.js","position":103,"original_position":103,"commit_id":"d6f174de150b5b1bf5565c195441d413e1ce027a","original_commit_id":"d6f174de150b5b1bf5565c195441d413e1ce027a","user":{"login":"johannes-scharlach","id":5310458,"avatar_url":"https://avatars.githubusercontent.com/u/5310458?v=3","gravatar_id":"","url":"https://api.github.com/users/johannes-scharlach","html_url":"https://github.com/johannes-scharlach","followers_url":"https://api.github.com/users/johannes-scharlach/followers","following_url":"https://api.github.com/users/johannes-scharlach/following{/other_user}","gists_url":"https://api.github.com/users/johannes-scharlach/gists{/gist_id}","starred_url":"https://api.github.com/users/johannes-scharlach/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/johannes-scharlach/subscriptions","organizations_url":"https://api.github.com/users/johannes-scharlach/orgs","repos_url":"https://api.github.com/users/johannes-scharlach/repos","events_url":"https://api.github.com/users/johannes-scharlach/events{/privacy}","received_events_url":"https://api.github.com/users/johannes-scharlach/received_events","type":"User","site_admin":false},"body":"btw: This is the same as\r\n```js\r\nconst clause = _.find(newAggregation)\r\n```","created_at":"2016-10-26T08:17:23Z","updated_at":"2016-10-26T08:17:23Z","html_url":"https://github.com/danpaz/bodybuilder/pull/71#discussion_r85070284","pull_request_url":"https://api.github.com/repos/danpaz/bodybuilder/pulls/71","_links":{"self":{"href":"https://api.github.com/repos/danpaz/bodybuilder/pulls/comments/85070284"},"html":{"href":"https://github.com/danpaz/bodybuilder/pull/71#discussion_r85070284"},"pull_request":{"href":"https://api.github.com/repos/danpaz/bodybuilder/pulls/71"}}},"pull_request":{"url":"https://api.github.com/repos/danpaz/bodybuilder/pulls/71","id":90818689,"html_url":"https://github.com/danpaz/bodybuilder/pull/71","diff_url":"https://github.com/danpaz/bodybuilder/pull/71.diff","patch_url":"https://github.com/danpaz/bodybuilder/pull/71.patch","issue_url":"https://api.github.com/repos/danpaz/bodybuilder/issues/71","number":71,"state":"open","locked":false,"title":"Feature generic query builder","user":{"login":"danpaz","id":5665333,"avatar_url":"https://avatars.githubusercontent.com/u/5665333?v=3","gravatar_id":"","url":"https://api.github.com/users/danpaz","html_url":"https://github.com/danpaz","followers_url":"https://api.github.com/users/danpaz/followers","following_url":"https://api.github.com/users/danpaz/following{/other_user}","gists_url":"https://api.github.com/users/danpaz/gists{/gist_id}","starred_url":"https://api.github.com/users/danpaz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danpaz/subscriptions","organizations_url":"https://api.github.com/users/danpaz/orgs","repos_url":"https://api.github.com/users/danpaz/repos","events_url":"https://api.github.com/users/danpaz/events{/privacy}","received_events_url":"https://api.github.com/users/danpaz/received_events","type":"User","site_admin":false},"body":"**For experimentation, not meant to merge**. \r\n\r\nLinked to #65 #70. Following patterns established in #64 and #16 (thanks @nfantone and @johannes-scharlach!).\r\n\r\nIntroduces a generic QueryBuilder that\r\n- Does not require definitions for every query that elasticsearch allows, instead it transparently builds a query clause depending on the number and type of arguments to the `query` function. \r\n- This means all query types should be build-able by bodybuilder and we can delete the entire src/queries directory.\r\n- Allows nesting queries in the query clause (needed for `nested`, `has_child` and `has_parent`) by passing a function as the last argument to `query`.\r\n- This pattern could be extended to filters (#64 is already quite similar) and aggregations.\r\n- Can we use this pattern to compose filters and queries, or filters and aggregations as in #64?\r\n\r\nSee tests for usage. Run tests using `babel-tape-runner test/query-builder.js | tap-spec`.\r\n\r\n🙇 ","created_at":"2016-10-25T14:25:39Z","updated_at":"2016-10-26T08:19:53Z","closed_at":null,"merged_at":null,"merge_commit_sha":"0f4ad83211c4c83c5148d6bdb1d88f426f4ac4dc","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/danpaz/bodybuilder/pulls/71/commits","review_comments_url":"https://api.github.com/repos/danpaz/bodybuilder/pulls/71/comments","review_comment_url":"https://api.github.com/repos/danpaz/bodybuilder/pulls/comments{/number}","comments_url":"https://api.github.com/repos/danpaz/bodybuilder/issues/71/comments","statuses_url":"https://api.github.com/repos/danpaz/bodybuilder/statuses/d6f174de150b5b1bf5565c195441d413e1ce027a","head":{"label":"danpaz:feature-generic-query-builder","ref":"feature-generic-query-builder","sha":"d6f174de150b5b1bf5565c195441d413e1ce027a","user":{"login":"danpaz","id":5665333,"avatar_url":"https://avatars.githubusercontent.com/u/5665333?v=3","gravatar_id":"","url":"https://api.github.com/users/danpaz","html_url":"https://github.com/danpaz","followers_url":"https://api.github.com/users/danpaz/followers","following_url":"https://api.github.com/users/danpaz/following{/other_user}","gists_url":"https://api.github.com/users/danpaz/gists{/gist_id}","starred_url":"https://api.github.com/users/danpaz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danpaz/subscriptions","organizations_url":"https://api.github.com/users/danpaz/orgs","repos_url":"https://api.github.com/users/danpaz/repos","events_url":"https://api.github.com/users/danpaz/events{/privacy}","received_events_url":"https://api.github.com/users/danpaz/received_events","type":"User","site_admin":false},"repo":{"id":40519241,"name":"bodybuilder","full_name":"danpaz/bodybuilder","owner":{"login":"danpaz","id":5665333,"avatar_url":"https://avatars.githubusercontent.com/u/5665333?v=3","gravatar_id":"","url":"https://api.github.com/users/danpaz","html_url":"https://github.com/danpaz","followers_url":"https://api.github.com/users/danpaz/followers","following_url":"https://api.github.com/users/danpaz/following{/other_user}","gists_url":"https://api.github.com/users/danpaz/gists{/gist_id}","starred_url":"https://api.github.com/users/danpaz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danpaz/subscriptions","organizations_url":"https://api.github.com/users/danpaz/orgs","repos_url":"https://api.github.com/users/danpaz/repos","events_url":"https://api.github.com/users/danpaz/events{/privacy}","received_events_url":"https://api.github.com/users/danpaz/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/danpaz/bodybuilder","description":"An elasticsearch query body builder :muscle:","fork":false,"url":"https://api.github.com/repos/danpaz/bodybuilder","forks_url":"https://api.github.com/repos/danpaz/bodybuilder/forks","keys_url":"https://api.github.com/repos/danpaz/bodybuilder/keys{/key_id}","collaborators_url":"https://api.github.com/repos/danpaz/bodybuilder/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/danpaz/bodybuilder/teams","hooks_url":"https://api.github.com/repos/danpaz/bodybuilder/hooks","issue_events_url":"https://api.github.com/repos/danpaz/bodybuilder/issues/events{/number}","events_url":"https://api.github.com/repos/danpaz/bodybuilder/events","assignees_url":"https://api.github.com/repos/danpaz/bodybuilder/assignees{/user}","branches_url":"https://api.github.com/repos/danpaz/bodybuilder/branches{/branch}","tags_url":"https://api.github.com/repos/danpaz/bodybuilder/tags","blobs_url":"https://api.github.com/repos/danpaz/bodybuilder/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/danpaz/bodybuilder/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/danpaz/bodybuilder/git/refs{/sha}","trees_url":"https://api.github.com/repos/danpaz/bodybuilder/git/trees{/sha}","statuses_url":"https://api.github.com/repos/danpaz/bodybuilder/statuses/{sha}","languages_url":"https://api.github.com/repos/danpaz/bodybuilder/languages","stargazers_url":"https://api.github.com/repos/danpaz/bodybuilder/stargazers","contributors_url":"https://api.github.com/repos/danpaz/bodybuilder/contributors","subscribers_url":"https://api.github.com/repos/danpaz/bodybuilder/subscribers","subscription_url":"https://api.github.com/repos/danpaz/bodybuilder/subscription","commits_url":"https://api.github.com/repos/danpaz/bodybuilder/commits{/sha}","git_commits_url":"https://api.github.com/repos/danpaz/bodybuilder/git/commits{/sha}","comments_url":"https://api.github.com/repos/danpaz/bodybuilder/comments{/number}","issue_comment_url":"https://api.github.com/repos/danpaz/bodybuilder/issues/comments{/number}","contents_url":"https://api.github.com/repos/danpaz/bodybuilder/contents/{+path}","compare_url":"https://api.github.com/repos/danpaz/bodybuilder/compare/{base}...{head}","merges_url":"https://api.github.com/repos/danpaz/bodybuilder/merges","archive_url":"https://api.github.com/repos/danpaz/bodybuilder/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/danpaz/bodybuilder/downloads","issues_url":"https://api.github.com/repos/danpaz/bodybuilder/issues{/number}","pulls_url":"https://api.github.com/repos/danpaz/bodybuilder/pulls{/number}","milestones_url":"https://api.github.com/repos/danpaz/bodybuilder/milestones{/number}","notifications_url":"https://api.github.com/repos/danpaz/bodybuilder/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/danpaz/bodybuilder/labels{/name}","releases_url":"https://api.github.com/repos/danpaz/bodybuilder/releases{/id}","deployments_url":"https://api.github.com/repos/danpaz/bodybuilder/deployments","created_at":"2015-08-11T03:27:19Z","updated_at":"2016-10-25T13:37:50Z","pushed_at":"2016-10-25T21:05:39Z","git_url":"git://github.com/danpaz/bodybuilder.git","ssh_url":"git@github.com:danpaz/bodybuilder.git","clone_url":"https://github.com/danpaz/bodybuilder.git","svn_url":"https://github.com/danpaz/bodybuilder","homepage":"http://bodybuilder.js.org","size":1672,"stargazers_count":201,"watchers_count":201,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":32,"mirror_url":null,"open_issues_count":13,"forks":32,"open_issues":13,"watchers":201,"default_branch":"master"}},"base":{"label":"danpaz:master","ref":"master","sha":"ae867c9feb6f28174b5699230848f08b62b726b2","user":{"login":"danpaz","id":5665333,"avatar_url":"https://avatars.githubusercontent.com/u/5665333?v=3","gravatar_id":"","url":"https://api.github.com/users/danpaz","html_url":"https://github.com/danpaz","followers_url":"https://api.github.com/users/danpaz/followers","following_url":"https://api.github.com/users/danpaz/following{/other_user}","gists_url":"https://api.github.com/users/danpaz/gists{/gist_id}","starred_url":"https://api.github.com/users/danpaz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danpaz/subscriptions","organizations_url":"https://api.github.com/users/danpaz/orgs","repos_url":"https://api.github.com/users/danpaz/repos","events_url":"https://api.github.com/users/danpaz/events{/privacy}","received_events_url":"https://api.github.com/users/danpaz/received_events","type":"User","site_admin":false},"repo":{"id":40519241,"name":"bodybuilder","full_name":"danpaz/bodybuilder","owner":{"login":"danpaz","id":5665333,"avatar_url":"https://avatars.githubusercontent.com/u/5665333?v=3","gravatar_id":"","url":"https://api.github.com/users/danpaz","html_url":"https://github.com/danpaz","followers_url":"https://api.github.com/users/danpaz/followers","following_url":"https://api.github.com/users/danpaz/following{/other_user}","gists_url":"https://api.github.com/users/danpaz/gists{/gist_id}","starred_url":"https://api.github.com/users/danpaz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danpaz/subscriptions","organizations_url":"https://api.github.com/users/danpaz/orgs","repos_url":"https://api.github.com/users/danpaz/repos","events_url":"https://api.github.com/users/danpaz/events{/privacy}","received_events_url":"https://api.github.com/users/danpaz/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/danpaz/bodybuilder","description":"An elasticsearch query body builder :muscle:","fork":false,"url":"https://api.github.com/repos/danpaz/bodybuilder","forks_url":"https://api.github.com/repos/danpaz/bodybuilder/forks","keys_url":"https://api.github.com/repos/danpaz/bodybuilder/keys{/key_id}","collaborators_url":"https://api.github.com/repos/danpaz/bodybuilder/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/danpaz/bodybuilder/teams","hooks_url":"https://api.github.com/repos/danpaz/bodybuilder/hooks","issue_events_url":"https://api.github.com/repos/danpaz/bodybuilder/issues/events{/number}","events_url":"https://api.github.com/repos/danpaz/bodybuilder/events","assignees_url":"https://api.github.com/repos/danpaz/bodybuilder/assignees{/user}","branches_url":"https://api.github.com/repos/danpaz/bodybuilder/branches{/branch}","tags_url":"https://api.github.com/repos/danpaz/bodybuilder/tags","blobs_url":"https://api.github.com/repos/danpaz/bodybuilder/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/danpaz/bodybuilder/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/danpaz/bodybuilder/git/refs{/sha}","trees_url":"https://api.github.com/repos/danpaz/bodybuilder/git/trees{/sha}","statuses_url":"https://api.github.com/repos/danpaz/bodybuilder/statuses/{sha}","languages_url":"https://api.github.com/repos/danpaz/bodybuilder/languages","stargazers_url":"https://api.github.com/repos/danpaz/bodybuilder/stargazers","contributors_url":"https://api.github.com/repos/danpaz/bodybuilder/contributors","subscribers_url":"https://api.github.com/repos/danpaz/bodybuilder/subscribers","subscription_url":"https://api.github.com/repos/danpaz/bodybuilder/subscription","commits_url":"https://api.github.com/repos/danpaz/bodybuilder/commits{/sha}","git_commits_url":"https://api.github.com/repos/danpaz/bodybuilder/git/commits{/sha}","comments_url":"https://api.github.com/repos/danpaz/bodybuilder/comments{/number}","issue_comment_url":"https://api.github.com/repos/danpaz/bodybuilder/issues/comments{/number}","contents_url":"https://api.github.com/repos/danpaz/bodybuilder/contents/{+path}","compare_url":"https://api.github.com/repos/danpaz/bodybuilder/compare/{base}...{head}","merges_url":"https://api.github.com/repos/danpaz/bodybuilder/merges","archive_url":"https://api.github.com/repos/danpaz/bodybuilder/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/danpaz/bodybuilder/downloads","issues_url":"https://api.github.com/repos/danpaz/bodybuilder/issues{/number}","pulls_url":"https://api.github.com/repos/danpaz/bodybuilder/pulls{/number}","milestones_url":"https://api.github.com/repos/danpaz/bodybuilder/milestones{/number}","notifications_url":"https://api.github.com/repos/danpaz/bodybuilder/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/danpaz/bodybuilder/labels{/name}","releases_url":"https://api.github.com/repos/danpaz/bodybuilder/releases{/id}","deployments_url":"https://api.github.com/repos/danpaz/bodybuilder/deployments","created_at":"2015-08-11T03:27:19Z","updated_at":"2016-10-25T13:37:50Z","pushed_at":"2016-10-25T21:05:39Z","git_url":"git://github.com/danpaz/bodybuilder.git","ssh_url":"git@github.com:danpaz/bodybuilder.git","clone_url":"https://github.com/danpaz/bodybuilder.git","svn_url":"https://github.com/danpaz/bodybuilder","homepage":"http://bodybuilder.js.org","size":1672,"stargazers_count":201,"watchers_count":201,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":32,"mirror_url":null,"open_issues_count":13,"forks":32,"open_issues":13,"watchers":201,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/danpaz/bodybuilder/pulls/71"},"html":{"href":"https://github.com/danpaz/bodybuilder/pull/71"},"issue":{"href":"https://api.github.com/repos/danpaz/bodybuilder/issues/71"},"comments":{"href":"https://api.github.com/repos/danpaz/bodybuilder/issues/71/comments"},"review_comments":{"href":"https://api.github.com/repos/danpaz/bodybuilder/pulls/71/comments"},"review_comment":{"href":"https://api.github.com/repos/danpaz/bodybuilder/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/danpaz/bodybuilder/pulls/71/commits"},"statuses":{"href":"https://api.github.com/repos/danpaz/bodybuilder/statuses/d6f174de150b5b1bf5565c195441d413e1ce027a"}}}}
{"actor":{"display_login":"johannes-scharlach"}}