{"action":"created","comment":{"url":"https://api.github.com/repos/Clever/optimus/pulls/comments/23471763","id":23471763,"diff_hunk":"@@ -0,0 +1,244 @@\n+package transforms\n+\n+import (\n+\t\"fmt\"\n+\t\"github.com/stretchr/testify/assert\"\n+\t\"gopkg.in/Clever/optimus.v3\"\n+\terrorSource \"gopkg.in/Clever/optimus.v3/sources/error\"\n+\t\"gopkg.in/Clever/optimus.v3/sources/slice\"\n+\t\"gopkg.in/Clever/optimus.v3/tests\"\n+\t\"testing\"\n+)\n+\n+var a = optimus.Row{\"k1\": \"v1\", \"k3\": \"v3\"}\n+var b = optimus.Row{\"k2\": \"v3\", \"k4\": \"v4\"}\n+var c = optimus.Row{\"k5\": \"v5\"}\n+\n+var joinTests = []struct {\n+\tleft, right, expected []optimus.Row\n+\tleftHash, rightHash   RowHasher\n+}{\n+\t// All of these tests use \"k1\" as the key, where none of the rows should match OTHER rows, only\n+\t// each other\n+\t{\n+\t\tleft:      []optimus.Row{},\n+\t\tright:     []optimus.Row{},\n+\t\texpected:  []optimus.Row{},\n+\t\tleftHash:  KeyHasher(\"k1\"),\n+\t\trightHash: KeyHasher(\"k1\"),\n+\t},\n+\t{\n+\t\tleft:  []optimus.Row{a},\n+\t\tright: []optimus.Row{a},\n+\t\texpected: []optimus.Row{\n+\t\t\t{\"left\": a, \"right\": a},\n+\t\t},\n+\t\tleftHash:  KeyHasher(\"k1\"),\n+\t\trightHash: KeyHasher(\"k1\"),\n+\t},\n+\t{\n+\t\tleft:  []optimus.Row{a},\n+\t\tright: []optimus.Row{b},\n+\t\texpected: []optimus.Row{\n+\t\t\t{\"left\": a},\n+\t\t\t{\"right\": b},\n+\t\t},\n+\t\tleftHash:  KeyHasher(\"k1\"),\n+\t\trightHash: KeyHasher(\"k1\"),\n+\t},\n+\t// Trick test where they hash to nil on both sides\n+\t{\n+\t\tleft:  []optimus.Row{c, b},\n+\t\tright: []optimus.Row{b, c},\n+\t\texpected: []optimus.Row{\n+\t\t\t{\"left\": c},\n+\t\t\t{\"left\": b},\n+\t\t\t{\"right\": b},\n+\t\t\t{\"right\": c},\n+\t\t},\n+\t\tleftHash:  KeyHasher(\"k1\"),\n+\t\trightHash: KeyHasher(\"k1\"),\n+\t},\n+\t{\n+\t\tleft:  []optimus.Row{a, b},\n+\t\tright: []optimus.Row{a},\n+\t\texpected: []optimus.Row{\n+\t\t\t{\"left\": a, \"right\": a},\n+\t\t\t{\"left\": b},\n+\t\t},\n+\t\tleftHash:  KeyHasher(\"k1\"),\n+\t\trightHash: KeyHasher(\"k1\"),\n+\t},\n+\t{\n+\t\tleft:  []optimus.Row{a},\n+\t\tright: []optimus.Row{a, b},\n+\t\texpected: []optimus.Row{\n+\t\t\t{\"left\": a, \"right\": a},\n+\t\t\t{\"right\": b},\n+\t\t},\n+\t\tleftHash:  KeyHasher(\"k1\"),\n+\t\trightHash: KeyHasher(\"k1\"),\n+\t},\n+\t{\n+\t\tleft:  []optimus.Row{a, a},\n+\t\tright: []optimus.Row{a, b},\n+\t\texpected: []optimus.Row{\n+\t\t\t{\"left\": a, \"right\": a},\n+\t\t\t{\"left\": a, \"right\": a},\n+\t\t\t{\"right\": b},\n+\t\t},\n+\t\tleftHash:  KeyHasher(\"k1\"),\n+\t\trightHash: KeyHasher(\"k1\"),\n+\t},\n+\t{\n+\t\tleft:  []optimus.Row{a, b},\n+\t\tright: []optimus.Row{a, a},\n+\t\texpected: []optimus.Row{\n+\t\t\t{\"left\": a, \"right\": a},\n+\t\t\t{\"left\": a, \"right\": a},\n+\t\t\t{\"left\": b},\n+\t\t},\n+\t\tleftHash:  KeyHasher(\"k1\"),\n+\t\trightHash: KeyHasher(\"k1\"),\n+\t},\n+\t{\n+\t\tleft:  []optimus.Row{a, a},\n+\t\tright: []optimus.Row{a, a},\n+\t\texpected: []optimus.Row{\n+\t\t\t{\"left\": a, \"right\": a},\n+\t\t\t{\"left\": a, \"right\": a},\n+\t\t\t{\"left\": a, \"right\": a},\n+\t\t\t{\"left\": a, \"right\": a},\n+\t\t},\n+\t\tleftHash:  KeyHasher(\"k1\"),\n+\t\trightHash: KeyHasher(\"k1\"),\n+\t},\n+\t// Now let's get fancy and have one test with different hashes\n+\t{\n+\t\tleft:  []optimus.Row{a},\n+\t\tright: []optimus.Row{b},\n+\t\texpected: []optimus.Row{\n+\t\t\t{\"left\": a, \"right\": b},\n+\t\t},\n+\t\tleftHash:  KeyHasher(\"k3\"),\n+\t\trightHash: KeyHasher(\"k2\"),\n+\t},\n+}\n+\n+// First, test that we pair correctly by just using an OuterJoin so everything comes through.\n+func TestPairSuccess(t *testing.T) {\n+\tfor _, joinTest := range joinTests {\n+\t\tleft := slice.New(joinTest.left)\n+\t\tright := slice.New(joinTest.right)\n+\n+\t\tpair := Pair(right, joinTest.leftHash, joinTest.rightHash, OuterJoin)\n+\t\ttable := optimus.Transform(left, pair)\n+\n+\t\tactual := tests.GetRows(table)\n+\n+\t\tassert.Equal(t, joinTest.expected, actual)\n+\t\tassert.Nil(t, table.Err())\n+\t}\n+}\n+\n+// Second, test that we filter correctinly on not-outer join by running the same tests with\n+// different join types, except filtering the expected array.\n+\n+var joinFilters = []struct {\n+\tjoinType PairType\n+\tfilter   func(optimus.Row) bool\n+}{\n+\t{\n+\t\tjoinType: InnerJoin,","path":"transforms/pair_test.go","position":152,"original_position":152,"commit_id":"79fd8b30b878653f0ccdc3fe54249acfc694bcea","original_commit_id":"5879fceca43d79b0deae44909db49c5da4d67ab2","user":{"login":"kvigen","id":5514539,"avatar_url":"https://avatars.githubusercontent.com/u/5514539?v=3","gravatar_id":"","url":"https://api.github.com/users/kvigen","html_url":"https://github.com/kvigen","followers_url":"https://api.github.com/users/kvigen/followers","following_url":"https://api.github.com/users/kvigen/following{/other_user}","gists_url":"https://api.github.com/users/kvigen/gists{/gist_id}","starred_url":"https://api.github.com/users/kvigen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kvigen/subscriptions","organizations_url":"https://api.github.com/users/kvigen/orgs","repos_url":"https://api.github.com/users/kvigen/repos","events_url":"https://api.github.com/users/kvigen/events{/privacy}","received_events_url":"https://api.github.com/users/kvigen/received_events","type":"User","site_admin":false},"body":"does it make sense to just combine outer join into these tests? we could have a filter that didn't filter anything out? that way we would do all the tests in the same way","created_at":"2015-01-23T19:09:23Z","updated_at":"2015-01-23T19:09:23Z","html_url":"https://github.com/Clever/optimus/pull/18#discussion_r23471763","pull_request_url":"https://api.github.com/repos/Clever/optimus/pulls/18","_links":{"self":{"href":"https://api.github.com/repos/Clever/optimus/pulls/comments/23471763"},"html":{"href":"https://github.com/Clever/optimus/pull/18#discussion_r23471763"},"pull_request":{"href":"https://api.github.com/repos/Clever/optimus/pulls/18"}}},"pull_request":{"url":"https://api.github.com/repos/Clever/optimus/pulls/18","id":27732147,"html_url":"https://github.com/Clever/optimus/pull/18","diff_url":"https://github.com/Clever/optimus/pull/18.diff","patch_url":"https://github.com/Clever/optimus/pull/18.patch","issue_url":"https://api.github.com/repos/Clever/optimus/issues/18","number":18,"state":"open","locked":false,"title":"transforms: add pair (join without merging rows)","user":{"login":"azylman","id":790102,"avatar_url":"https://avatars.githubusercontent.com/u/790102?v=3","gravatar_id":"","url":"https://api.github.com/users/azylman","html_url":"https://github.com/azylman","followers_url":"https://api.github.com/users/azylman/followers","following_url":"https://api.github.com/users/azylman/following{/other_user}","gists_url":"https://api.github.com/users/azylman/gists{/gist_id}","starred_url":"https://api.github.com/users/azylman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/azylman/subscriptions","organizations_url":"https://api.github.com/users/azylman/orgs","repos_url":"https://api.github.com/users/azylman/repos","events_url":"https://api.github.com/users/azylman/events{/privacy}","received_events_url":"https://api.github.com/users/azylman/received_events","type":"User","site_admin":false},"body":"","created_at":"2015-01-21T03:04:44Z","updated_at":"2015-01-23T19:09:23Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c9ff0c61ac1eb28a07ccbced578c8c78a9ffbc69","assignee":{"login":"kvigen","id":5514539,"avatar_url":"https://avatars.githubusercontent.com/u/5514539?v=3","gravatar_id":"","url":"https://api.github.com/users/kvigen","html_url":"https://github.com/kvigen","followers_url":"https://api.github.com/users/kvigen/followers","following_url":"https://api.github.com/users/kvigen/following{/other_user}","gists_url":"https://api.github.com/users/kvigen/gists{/gist_id}","starred_url":"https://api.github.com/users/kvigen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kvigen/subscriptions","organizations_url":"https://api.github.com/users/kvigen/orgs","repos_url":"https://api.github.com/users/kvigen/repos","events_url":"https://api.github.com/users/kvigen/events{/privacy}","received_events_url":"https://api.github.com/users/kvigen/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/Clever/optimus/pulls/18/commits","review_comments_url":"https://api.github.com/repos/Clever/optimus/pulls/18/comments","review_comment_url":"https://api.github.com/repos/Clever/optimus/pulls/comments/{number}","comments_url":"https://api.github.com/repos/Clever/optimus/issues/18/comments","statuses_url":"https://api.github.com/repos/Clever/optimus/statuses/79fd8b30b878653f0ccdc3fe54249acfc694bcea","head":{"label":"Clever:generic-pair","ref":"generic-pair","sha":"79fd8b30b878653f0ccdc3fe54249acfc694bcea","user":{"login":"Clever","id":1885509,"avatar_url":"https://avatars.githubusercontent.com/u/1885509?v=3","gravatar_id":"","url":"https://api.github.com/users/Clever","html_url":"https://github.com/Clever","followers_url":"https://api.github.com/users/Clever/followers","following_url":"https://api.github.com/users/Clever/following{/other_user}","gists_url":"https://api.github.com/users/Clever/gists{/gist_id}","starred_url":"https://api.github.com/users/Clever/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Clever/subscriptions","organizations_url":"https://api.github.com/users/Clever/orgs","repos_url":"https://api.github.com/users/Clever/repos","events_url":"https://api.github.com/users/Clever/events{/privacy}","received_events_url":"https://api.github.com/users/Clever/received_events","type":"Organization","site_admin":false},"repo":{"id":19153709,"name":"optimus","full_name":"Clever/optimus","owner":{"login":"Clever","id":1885509,"avatar_url":"https://avatars.githubusercontent.com/u/1885509?v=3","gravatar_id":"","url":"https://api.github.com/users/Clever","html_url":"https://github.com/Clever","followers_url":"https://api.github.com/users/Clever/followers","following_url":"https://api.github.com/users/Clever/following{/other_user}","gists_url":"https://api.github.com/users/Clever/gists{/gist_id}","starred_url":"https://api.github.com/users/Clever/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Clever/subscriptions","organizations_url":"https://api.github.com/users/Clever/orgs","repos_url":"https://api.github.com/users/Clever/repos","events_url":"https://api.github.com/users/Clever/events{/privacy}","received_events_url":"https://api.github.com/users/Clever/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Clever/optimus","description":"Concurrently extract, transform, and load tables of data in Go","fork":false,"url":"https://api.github.com/repos/Clever/optimus","forks_url":"https://api.github.com/repos/Clever/optimus/forks","keys_url":"https://api.github.com/repos/Clever/optimus/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Clever/optimus/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Clever/optimus/teams","hooks_url":"https://api.github.com/repos/Clever/optimus/hooks","issue_events_url":"https://api.github.com/repos/Clever/optimus/issues/events{/number}","events_url":"https://api.github.com/repos/Clever/optimus/events","assignees_url":"https://api.github.com/repos/Clever/optimus/assignees{/user}","branches_url":"https://api.github.com/repos/Clever/optimus/branches{/branch}","tags_url":"https://api.github.com/repos/Clever/optimus/tags","blobs_url":"https://api.github.com/repos/Clever/optimus/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Clever/optimus/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Clever/optimus/git/refs{/sha}","trees_url":"https://api.github.com/repos/Clever/optimus/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Clever/optimus/statuses/{sha}","languages_url":"https://api.github.com/repos/Clever/optimus/languages","stargazers_url":"https://api.github.com/repos/Clever/optimus/stargazers","contributors_url":"https://api.github.com/repos/Clever/optimus/contributors","subscribers_url":"https://api.github.com/repos/Clever/optimus/subscribers","subscription_url":"https://api.github.com/repos/Clever/optimus/subscription","commits_url":"https://api.github.com/repos/Clever/optimus/commits{/sha}","git_commits_url":"https://api.github.com/repos/Clever/optimus/git/commits{/sha}","comments_url":"https://api.github.com/repos/Clever/optimus/comments{/number}","issue_comment_url":"https://api.github.com/repos/Clever/optimus/issues/comments/{number}","contents_url":"https://api.github.com/repos/Clever/optimus/contents/{+path}","compare_url":"https://api.github.com/repos/Clever/optimus/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Clever/optimus/merges","archive_url":"https://api.github.com/repos/Clever/optimus/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Clever/optimus/downloads","issues_url":"https://api.github.com/repos/Clever/optimus/issues{/number}","pulls_url":"https://api.github.com/repos/Clever/optimus/pulls{/number}","milestones_url":"https://api.github.com/repos/Clever/optimus/milestones{/number}","notifications_url":"https://api.github.com/repos/Clever/optimus/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Clever/optimus/labels{/name}","releases_url":"https://api.github.com/repos/Clever/optimus/releases{/id}","created_at":"2014-04-25T17:02:24Z","updated_at":"2015-01-23T00:05:32Z","pushed_at":"2015-01-23T19:05:15Z","git_url":"git://github.com/Clever/optimus.git","ssh_url":"git@github.com:Clever/optimus.git","clone_url":"https://github.com/Clever/optimus.git","svn_url":"https://github.com/Clever/optimus","homepage":"","size":766,"stargazers_count":5,"watchers_count":5,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":2,"forks":1,"open_issues":2,"watchers":5,"default_branch":"master"}},"base":{"label":"Clever:master","ref":"master","sha":"d3e7a0b74c4b6ee7bd8b8068eaf00b42f50e1cc3","user":{"login":"Clever","id":1885509,"avatar_url":"https://avatars.githubusercontent.com/u/1885509?v=3","gravatar_id":"","url":"https://api.github.com/users/Clever","html_url":"https://github.com/Clever","followers_url":"https://api.github.com/users/Clever/followers","following_url":"https://api.github.com/users/Clever/following{/other_user}","gists_url":"https://api.github.com/users/Clever/gists{/gist_id}","starred_url":"https://api.github.com/users/Clever/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Clever/subscriptions","organizations_url":"https://api.github.com/users/Clever/orgs","repos_url":"https://api.github.com/users/Clever/repos","events_url":"https://api.github.com/users/Clever/events{/privacy}","received_events_url":"https://api.github.com/users/Clever/received_events","type":"Organization","site_admin":false},"repo":{"id":19153709,"name":"optimus","full_name":"Clever/optimus","owner":{"login":"Clever","id":1885509,"avatar_url":"https://avatars.githubusercontent.com/u/1885509?v=3","gravatar_id":"","url":"https://api.github.com/users/Clever","html_url":"https://github.com/Clever","followers_url":"https://api.github.com/users/Clever/followers","following_url":"https://api.github.com/users/Clever/following{/other_user}","gists_url":"https://api.github.com/users/Clever/gists{/gist_id}","starred_url":"https://api.github.com/users/Clever/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Clever/subscriptions","organizations_url":"https://api.github.com/users/Clever/orgs","repos_url":"https://api.github.com/users/Clever/repos","events_url":"https://api.github.com/users/Clever/events{/privacy}","received_events_url":"https://api.github.com/users/Clever/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Clever/optimus","description":"Concurrently extract, transform, and load tables of data in Go","fork":false,"url":"https://api.github.com/repos/Clever/optimus","forks_url":"https://api.github.com/repos/Clever/optimus/forks","keys_url":"https://api.github.com/repos/Clever/optimus/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Clever/optimus/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Clever/optimus/teams","hooks_url":"https://api.github.com/repos/Clever/optimus/hooks","issue_events_url":"https://api.github.com/repos/Clever/optimus/issues/events{/number}","events_url":"https://api.github.com/repos/Clever/optimus/events","assignees_url":"https://api.github.com/repos/Clever/optimus/assignees{/user}","branches_url":"https://api.github.com/repos/Clever/optimus/branches{/branch}","tags_url":"https://api.github.com/repos/Clever/optimus/tags","blobs_url":"https://api.github.com/repos/Clever/optimus/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Clever/optimus/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Clever/optimus/git/refs{/sha}","trees_url":"https://api.github.com/repos/Clever/optimus/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Clever/optimus/statuses/{sha}","languages_url":"https://api.github.com/repos/Clever/optimus/languages","stargazers_url":"https://api.github.com/repos/Clever/optimus/stargazers","contributors_url":"https://api.github.com/repos/Clever/optimus/contributors","subscribers_url":"https://api.github.com/repos/Clever/optimus/subscribers","subscription_url":"https://api.github.com/repos/Clever/optimus/subscription","commits_url":"https://api.github.com/repos/Clever/optimus/commits{/sha}","git_commits_url":"https://api.github.com/repos/Clever/optimus/git/commits{/sha}","comments_url":"https://api.github.com/repos/Clever/optimus/comments{/number}","issue_comment_url":"https://api.github.com/repos/Clever/optimus/issues/comments/{number}","contents_url":"https://api.github.com/repos/Clever/optimus/contents/{+path}","compare_url":"https://api.github.com/repos/Clever/optimus/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Clever/optimus/merges","archive_url":"https://api.github.com/repos/Clever/optimus/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Clever/optimus/downloads","issues_url":"https://api.github.com/repos/Clever/optimus/issues{/number}","pulls_url":"https://api.github.com/repos/Clever/optimus/pulls{/number}","milestones_url":"https://api.github.com/repos/Clever/optimus/milestones{/number}","notifications_url":"https://api.github.com/repos/Clever/optimus/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Clever/optimus/labels{/name}","releases_url":"https://api.github.com/repos/Clever/optimus/releases{/id}","created_at":"2014-04-25T17:02:24Z","updated_at":"2015-01-23T00:05:32Z","pushed_at":"2015-01-23T19:05:15Z","git_url":"git://github.com/Clever/optimus.git","ssh_url":"git@github.com:Clever/optimus.git","clone_url":"https://github.com/Clever/optimus.git","svn_url":"https://github.com/Clever/optimus","homepage":"","size":766,"stargazers_count":5,"watchers_count":5,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":2,"forks":1,"open_issues":2,"watchers":5,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Clever/optimus/pulls/18"},"html":{"href":"https://github.com/Clever/optimus/pull/18"},"issue":{"href":"https://api.github.com/repos/Clever/optimus/issues/18"},"comments":{"href":"https://api.github.com/repos/Clever/optimus/issues/18/comments"},"review_comments":{"href":"https://api.github.com/repos/Clever/optimus/pulls/18/comments"},"review_comment":{"href":"https://api.github.com/repos/Clever/optimus/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/Clever/optimus/pulls/18/commits"},"statuses":{"href":"https://api.github.com/repos/Clever/optimus/statuses/79fd8b30b878653f0ccdc3fe54249acfc694bcea"}}}}