{"action":"opened","number":13,"pull_request":{"url":"https://api.github.com/repos/russross/meddler/pulls/13","id":47178802,"html_url":"https://github.com/russross/meddler/pull/13","diff_url":"https://github.com/russross/meddler/pull/13.diff","patch_url":"https://github.com/russross/meddler/pull/13.patch","issue_url":"https://api.github.com/repos/russross/meddler/issues/13","number":13,"state":"open","locked":false,"title":"Provide a hook function to cache prepared statements","user":{"login":"PuerkitoBio","id":692384,"avatar_url":"https://avatars.githubusercontent.com/u/692384?v=3","gravatar_id":"","url":"https://api.github.com/users/PuerkitoBio","html_url":"https://github.com/PuerkitoBio","followers_url":"https://api.github.com/users/PuerkitoBio/followers","following_url":"https://api.github.com/users/PuerkitoBio/following{/other_user}","gists_url":"https://api.github.com/users/PuerkitoBio/gists{/gist_id}","starred_url":"https://api.github.com/users/PuerkitoBio/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/PuerkitoBio/subscriptions","organizations_url":"https://api.github.com/users/PuerkitoBio/orgs","repos_url":"https://api.github.com/users/PuerkitoBio/repos","events_url":"https://api.github.com/users/PuerkitoBio/events{/privacy}","received_events_url":"https://api.github.com/users/PuerkitoBio/received_events","type":"User","site_admin":false},"body":"Hi Russ,\r\n\r\nI know you mentioned in #4 that you were thinking about a way to add this support, but for my use-case I've used a simple and minimally intrusive solution with a function variable that provides a hook that gets called before every statement is executed (see `StmtCacheFunc` comment in the PR).\r\n\r\nIt is obviously quite flexible, but personally I've used it like this:\r\n\r\n```go\r\nvar lruCache *lru.Cache // github.com/hashicorp/golang-lru\r\n\r\nfunc init() {\r\n    var err error\r\n    lruCache, err = lru.NewWithEvict(50, stmtEvicted) // 50 is the max number of statements to cache\r\n    if err != nil {\r\n      // ...\r\n    }\r\n    meddler.StmtCacheFunc = stmtCache\r\n}\r\n\r\nfunc stmtCache(db meddler.DB, q string) (*sql.Stmt, error) {\r\n\tswitch db := db.(type) {\r\n\tcase *sql.DB:\r\n\t\tv, ok := lruCache.Get(q)\r\n\t\tif !ok {\r\n\t\t\ts, err := db.Prepare(q)\r\n\t\t\tif err != nil {\r\n\t\t\t\treturn nil, err\r\n\t\t\t}\r\n\t\t\tif lruCache.Add(q, s) {\r\n\t\t\t\t// a statement has been evicted, can e.g. log if that's interesting\r\n\t\t\t}\r\n\t\t\treturn s, nil\r\n\t\t}\r\n\t\treturn v.(*sql.Stmt), nil\r\n\r\n\tdefault:\r\n\t\t// do not prepare statements for transactions - too little reuse\r\n\t\t// to be worth it. (see http://go-database-sql.org/prepared.html)\r\n\t\treturn nil, nil\r\n\t}\r\n}\r\n\r\n// cleanup on cache eviction\r\nfunc stmtEvicted(k, v interface{}) {\r\n\tstmt := v.(*sql.Stmt)\r\n\tstmt.Close()\r\n}\r\n```\r\n\r\nWould that be something you'd like to add? I could also add the `*meddler.Database` (probably as first argument) in case some people use the same queries for various drivers (although they could use the `meddler.DB` as part of the cache key).\r\n\r\nThanks,\r\nMartin\r\n","created_at":"2015-10-08T16:58:13Z","updated_at":"2015-10-08T16:58:13Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/russross/meddler/pulls/13/commits","review_comments_url":"https://api.github.com/repos/russross/meddler/pulls/13/comments","review_comment_url":"https://api.github.com/repos/russross/meddler/pulls/comments{/number}","comments_url":"https://api.github.com/repos/russross/meddler/issues/13/comments","statuses_url":"https://api.github.com/repos/russross/meddler/statuses/a7ac28e3d28e30c49e1c29d60afd20220985c5fd","head":{"label":"PuerkitoBio:master","ref":"master","sha":"a7ac28e3d28e30c49e1c29d60afd20220985c5fd","user":{"login":"PuerkitoBio","id":692384,"avatar_url":"https://avatars.githubusercontent.com/u/692384?v=3","gravatar_id":"","url":"https://api.github.com/users/PuerkitoBio","html_url":"https://github.com/PuerkitoBio","followers_url":"https://api.github.com/users/PuerkitoBio/followers","following_url":"https://api.github.com/users/PuerkitoBio/following{/other_user}","gists_url":"https://api.github.com/users/PuerkitoBio/gists{/gist_id}","starred_url":"https://api.github.com/users/PuerkitoBio/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/PuerkitoBio/subscriptions","organizations_url":"https://api.github.com/users/PuerkitoBio/orgs","repos_url":"https://api.github.com/users/PuerkitoBio/repos","events_url":"https://api.github.com/users/PuerkitoBio/events{/privacy}","received_events_url":"https://api.github.com/users/PuerkitoBio/received_events","type":"User","site_admin":false},"repo":{"id":35501353,"name":"meddler","full_name":"PuerkitoBio/meddler","owner":{"login":"PuerkitoBio","id":692384,"avatar_url":"https://avatars.githubusercontent.com/u/692384?v=3","gravatar_id":"","url":"https://api.github.com/users/PuerkitoBio","html_url":"https://github.com/PuerkitoBio","followers_url":"https://api.github.com/users/PuerkitoBio/followers","following_url":"https://api.github.com/users/PuerkitoBio/following{/other_user}","gists_url":"https://api.github.com/users/PuerkitoBio/gists{/gist_id}","starred_url":"https://api.github.com/users/PuerkitoBio/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/PuerkitoBio/subscriptions","organizations_url":"https://api.github.com/users/PuerkitoBio/orgs","repos_url":"https://api.github.com/users/PuerkitoBio/repos","events_url":"https://api.github.com/users/PuerkitoBio/events{/privacy}","received_events_url":"https://api.github.com/users/PuerkitoBio/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/PuerkitoBio/meddler","description":"conversion between sql and structs in go","fork":true,"url":"https://api.github.com/repos/PuerkitoBio/meddler","forks_url":"https://api.github.com/repos/PuerkitoBio/meddler/forks","keys_url":"https://api.github.com/repos/PuerkitoBio/meddler/keys{/key_id}","collaborators_url":"https://api.github.com/repos/PuerkitoBio/meddler/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/PuerkitoBio/meddler/teams","hooks_url":"https://api.github.com/repos/PuerkitoBio/meddler/hooks","issue_events_url":"https://api.github.com/repos/PuerkitoBio/meddler/issues/events{/number}","events_url":"https://api.github.com/repos/PuerkitoBio/meddler/events","assignees_url":"https://api.github.com/repos/PuerkitoBio/meddler/assignees{/user}","branches_url":"https://api.github.com/repos/PuerkitoBio/meddler/branches{/branch}","tags_url":"https://api.github.com/repos/PuerkitoBio/meddler/tags","blobs_url":"https://api.github.com/repos/PuerkitoBio/meddler/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/PuerkitoBio/meddler/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/PuerkitoBio/meddler/git/refs{/sha}","trees_url":"https://api.github.com/repos/PuerkitoBio/meddler/git/trees{/sha}","statuses_url":"https://api.github.com/repos/PuerkitoBio/meddler/statuses/{sha}","languages_url":"https://api.github.com/repos/PuerkitoBio/meddler/languages","stargazers_url":"https://api.github.com/repos/PuerkitoBio/meddler/stargazers","contributors_url":"https://api.github.com/repos/PuerkitoBio/meddler/contributors","subscribers_url":"https://api.github.com/repos/PuerkitoBio/meddler/subscribers","subscription_url":"https://api.github.com/repos/PuerkitoBio/meddler/subscription","commits_url":"https://api.github.com/repos/PuerkitoBio/meddler/commits{/sha}","git_commits_url":"https://api.github.com/repos/PuerkitoBio/meddler/git/commits{/sha}","comments_url":"https://api.github.com/repos/PuerkitoBio/meddler/comments{/number}","issue_comment_url":"https://api.github.com/repos/PuerkitoBio/meddler/issues/comments{/number}","contents_url":"https://api.github.com/repos/PuerkitoBio/meddler/contents/{+path}","compare_url":"https://api.github.com/repos/PuerkitoBio/meddler/compare/{base}...{head}","merges_url":"https://api.github.com/repos/PuerkitoBio/meddler/merges","archive_url":"https://api.github.com/repos/PuerkitoBio/meddler/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/PuerkitoBio/meddler/downloads","issues_url":"https://api.github.com/repos/PuerkitoBio/meddler/issues{/number}","pulls_url":"https://api.github.com/repos/PuerkitoBio/meddler/pulls{/number}","milestones_url":"https://api.github.com/repos/PuerkitoBio/meddler/milestones{/number}","notifications_url":"https://api.github.com/repos/PuerkitoBio/meddler/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/PuerkitoBio/meddler/labels{/name}","releases_url":"https://api.github.com/repos/PuerkitoBio/meddler/releases{/id}","created_at":"2015-05-12T17:00:19Z","updated_at":"2015-05-12T17:00:19Z","pushed_at":"2015-05-21T02:23:02Z","git_url":"git://github.com/PuerkitoBio/meddler.git","ssh_url":"git@github.com:PuerkitoBio/meddler.git","clone_url":"https://github.com/PuerkitoBio/meddler.git","svn_url":"https://github.com/PuerkitoBio/meddler","homepage":"","size":171,"stargazers_count":0,"watchers_count":0,"language":"Go","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":"russross:master","ref":"master","sha":"f742b0f9424f3bfaffe189e921d734608929e84f","user":{"login":"russross","id":65428,"avatar_url":"https://avatars.githubusercontent.com/u/65428?v=3","gravatar_id":"","url":"https://api.github.com/users/russross","html_url":"https://github.com/russross","followers_url":"https://api.github.com/users/russross/followers","following_url":"https://api.github.com/users/russross/following{/other_user}","gists_url":"https://api.github.com/users/russross/gists{/gist_id}","starred_url":"https://api.github.com/users/russross/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/russross/subscriptions","organizations_url":"https://api.github.com/users/russross/orgs","repos_url":"https://api.github.com/users/russross/repos","events_url":"https://api.github.com/users/russross/events{/privacy}","received_events_url":"https://api.github.com/users/russross/received_events","type":"User","site_admin":false},"repo":{"id":10976257,"name":"meddler","full_name":"russross/meddler","owner":{"login":"russross","id":65428,"avatar_url":"https://avatars.githubusercontent.com/u/65428?v=3","gravatar_id":"","url":"https://api.github.com/users/russross","html_url":"https://github.com/russross","followers_url":"https://api.github.com/users/russross/followers","following_url":"https://api.github.com/users/russross/following{/other_user}","gists_url":"https://api.github.com/users/russross/gists{/gist_id}","starred_url":"https://api.github.com/users/russross/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/russross/subscriptions","organizations_url":"https://api.github.com/users/russross/orgs","repos_url":"https://api.github.com/users/russross/repos","events_url":"https://api.github.com/users/russross/events{/privacy}","received_events_url":"https://api.github.com/users/russross/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/russross/meddler","description":"conversion between sql and structs in go","fork":false,"url":"https://api.github.com/repos/russross/meddler","forks_url":"https://api.github.com/repos/russross/meddler/forks","keys_url":"https://api.github.com/repos/russross/meddler/keys{/key_id}","collaborators_url":"https://api.github.com/repos/russross/meddler/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/russross/meddler/teams","hooks_url":"https://api.github.com/repos/russross/meddler/hooks","issue_events_url":"https://api.github.com/repos/russross/meddler/issues/events{/number}","events_url":"https://api.github.com/repos/russross/meddler/events","assignees_url":"https://api.github.com/repos/russross/meddler/assignees{/user}","branches_url":"https://api.github.com/repos/russross/meddler/branches{/branch}","tags_url":"https://api.github.com/repos/russross/meddler/tags","blobs_url":"https://api.github.com/repos/russross/meddler/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/russross/meddler/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/russross/meddler/git/refs{/sha}","trees_url":"https://api.github.com/repos/russross/meddler/git/trees{/sha}","statuses_url":"https://api.github.com/repos/russross/meddler/statuses/{sha}","languages_url":"https://api.github.com/repos/russross/meddler/languages","stargazers_url":"https://api.github.com/repos/russross/meddler/stargazers","contributors_url":"https://api.github.com/repos/russross/meddler/contributors","subscribers_url":"https://api.github.com/repos/russross/meddler/subscribers","subscription_url":"https://api.github.com/repos/russross/meddler/subscription","commits_url":"https://api.github.com/repos/russross/meddler/commits{/sha}","git_commits_url":"https://api.github.com/repos/russross/meddler/git/commits{/sha}","comments_url":"https://api.github.com/repos/russross/meddler/comments{/number}","issue_comment_url":"https://api.github.com/repos/russross/meddler/issues/comments{/number}","contents_url":"https://api.github.com/repos/russross/meddler/contents/{+path}","compare_url":"https://api.github.com/repos/russross/meddler/compare/{base}...{head}","merges_url":"https://api.github.com/repos/russross/meddler/merges","archive_url":"https://api.github.com/repos/russross/meddler/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/russross/meddler/downloads","issues_url":"https://api.github.com/repos/russross/meddler/issues{/number}","pulls_url":"https://api.github.com/repos/russross/meddler/pulls{/number}","milestones_url":"https://api.github.com/repos/russross/meddler/milestones{/number}","notifications_url":"https://api.github.com/repos/russross/meddler/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/russross/meddler/labels{/name}","releases_url":"https://api.github.com/repos/russross/meddler/releases{/id}","created_at":"2013-06-26T18:58:00Z","updated_at":"2015-09-23T09:12:29Z","pushed_at":"2015-08-26T19:24:28Z","git_url":"git://github.com/russross/meddler.git","ssh_url":"git@github.com:russross/meddler.git","clone_url":"https://github.com/russross/meddler.git","svn_url":"https://github.com/russross/meddler","homepage":"","size":394,"stargazers_count":164,"watchers_count":164,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":12,"mirror_url":null,"open_issues_count":5,"forks":12,"open_issues":5,"watchers":164,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/russross/meddler/pulls/13"},"html":{"href":"https://github.com/russross/meddler/pull/13"},"issue":{"href":"https://api.github.com/repos/russross/meddler/issues/13"},"comments":{"href":"https://api.github.com/repos/russross/meddler/issues/13/comments"},"review_comments":{"href":"https://api.github.com/repos/russross/meddler/pulls/13/comments"},"review_comment":{"href":"https://api.github.com/repos/russross/meddler/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/russross/meddler/pulls/13/commits"},"statuses":{"href":"https://api.github.com/repos/russross/meddler/statuses/a7ac28e3d28e30c49e1c29d60afd20220985c5fd"}},"merged":false,"mergeable":null,"mergeable_state":"unknown","merged_by":null,"comments":0,"review_comments":0,"commits":2,"additions":61,"deletions":8,"changed_files":2}}