1
0
Fork 0

Org stat endpoints & queries

This commit is contained in:
Gregory Eremin 2015-03-06 23:29:26 +07:00
parent 7d38440126
commit 3e27fd11ae
6 changed files with 207 additions and 2 deletions

View File

@ -15,7 +15,7 @@ type Contrib struct {
} }
const saveContribQuery = ` const saveContribQuery = `
insert into contributions (week, author, owner, repo, commits, additions, deletions) insert into contribs (week, author, owner, repo, commits, additions, deletions)
values (:week, :author, :owner, :repo, :commits, :additions, :deletions) values (:week, :author, :owner, :repo, :commits, :additions, :deletions)
on duplicate key update on duplicate key update
commits=values(commits), additions=values(additions), deletions=values(deletions)` commits=values(commits), additions=values(additions), deletions=values(deletions)`

View File

@ -34,9 +34,13 @@ func mustSelect(dest interface{}, query string, args ...interface{}) {
func measure(op string, start time.Time) { func measure(op string, start time.Time) {
duration := time.Since(start).Nanoseconds() duration := time.Since(start).Nanoseconds()
outcome := "succeeded" outcome := "succeeded"
if err := recover(); err != nil { err := recover()
if err != nil {
outcome = "failed" outcome = "failed"
} }
log.Printf("Operation %s %s; time: %d (%dms)\n", op, outcome, duration, duration/1000000) log.Printf("Operation %s %s; time: %d (%dms)\n", op, outcome, duration, duration/1000000)
if err != nil {
panic(err)
}
} }

163
db/stat.go Normal file
View File

@ -0,0 +1,163 @@
package db
import (
"net/http"
"strconv"
"time"
)
type (
StatRequest struct {
Org string
Team string
User string
From int64
To int64
}
StatItem struct {
Item string `json:"item"`
Value int `json:"value"`
}
StatPoint struct {
StatItem
Timestamp uint64 `json:"ts"`
}
)
const orgReposTopQuery = `
select
c.repo as item,
sum(c.commits) as value
from contribs c
join members m on
c.author = m.user and
c.owner = m.org
where
m.id is not null and
c.owner = ? and
c.week >= ? and
c.week <= ?
group by item
order by value desc`
const orgReposActivityQuery = `
select
c.week as ts,
c.repo as item,
sum(c.commits) as value
from contribs c
join members m on
c.author = m.user and
c.owner = m.org
where
m.id is not null and
c.owner = ? and
c.week >= ? and
c.week <= ?
group by ts, item
order by ts, item`
const orgTeamsTopQuery = `
select
t.name as item,
sum(c.commits) value
from contribs c
join members m on
c.author = m.user and
c.owner = m.org
join teams t on
m.team_id = t.id
where
m.id is not null and
c.owner = ? and
c.week >= ? and
c.week <= ?
group by item
order by value desc`
const orgTeamsActivityQuery = `
select
c.week as ts,
t.name as item,
sum(c.commits) as value
from contribs c
join members m on
c.author = m.user and
c.owner = m.org
join teams t on
m.team_id = t.id
where
m.id is not null and
c.owner = ? and
c.week >= ? and
c.week <= ?
group by ts, item
order by ts, item`
const orgUsersTopQuery = `
select
c.author as item,
sum(c.commits) value
from contribs c
join members m on
c.author = m.user and
c.owner = m.org
where
m.id is not null and
c.owner = ? and
c.week >= ? and
c.week <= ?
group by item
order by value desc`
func StatOrgReposTop(r *StatRequest) (res []StatItem) {
defer measure("StatOrgReposTop", time.Now())
mustSelect(&res, orgReposTopQuery, r.Org, r.From, r.To)
return
}
func StatOrgReposActivity(r *StatRequest) (res []StatPoint) {
defer measure("StatOrgReposActivity", time.Now())
mustSelect(&res, orgReposActivityQuery, r.Org, r.From, r.To)
return
}
func StatOrgTeamsTop(r *StatRequest) (res []StatItem) {
defer measure("StatOrgTeamsTop", time.Now())
mustSelect(&res, orgTeamsTopQuery, r.Org, r.From, r.To)
return
}
func StatOrgTeamsActivity(r *StatRequest) (res []StatPoint) {
defer measure("StatOrgTeamsActivity", time.Now())
mustSelect(&res, orgTeamsActivityQuery, r.Org, r.From, r.To)
return
}
func StatOrgUsersTop(r *StatRequest) (res []StatItem) {
defer measure("StatOrgUsersTop", time.Now())
mustSelect(&res, orgUsersTopQuery, r.Org, r.From, r.To)
return
}
func ParseRequest(r *http.Request) *StatRequest {
var err error
var from, to int64
if len(r.FormValue("from")) > 0 {
if from, err = strconv.ParseInt(r.FormValue("from"), 10, 64); err != nil {
panic(err)
}
}
if len(r.FormValue("to")) > 0 {
if to, err = strconv.ParseInt(r.FormValue("to"), 10, 64); err != nil {
panic(err)
}
}
return &StatRequest{
Org: r.FormValue("org"),
Team: r.FormValue("team"),
User: r.FormValue("user"),
From: from,
To: to,
}
}

View File

@ -6,6 +6,7 @@ import (
type Team struct { type Team struct {
ID uint64 `json:"id"` ID uint64 `json:"id"`
Slug string `json:"slug"`
Owner string `json:"owner"` Owner string `json:"owner"`
Name string `json:"name"` Name string `json:"name"`
} }

View File

@ -31,6 +31,11 @@ func init() {
http.HandleFunc("/api/orgs", apiOrgsHandler) http.HandleFunc("/api/orgs", apiOrgsHandler)
http.HandleFunc("/api/teams", apiTeamsHandler) http.HandleFunc("/api/teams", apiTeamsHandler)
http.HandleFunc("/api/repos", apiReposHandler) http.HandleFunc("/api/repos", apiReposHandler)
http.HandleFunc("/api/stat/repos/top", statOrgReposTop)
http.HandleFunc("/api/stat/repos/activity", statOrgReposActivity)
http.HandleFunc("/api/stat/teams/top", statOrgTeamsTop)
http.HandleFunc("/api/stat/teams/activity", statOrgTeamsActivity)
http.HandleFunc("/api/stat/users/top", statOrgUsersTop)
} }
func Start() { func Start() {

32
server/stat.go Normal file
View File

@ -0,0 +1,32 @@
package server
import (
"net/http"
"github.com/localhots/empact/db"
)
func statOrgReposTop(w http.ResponseWriter, r *http.Request) {
top := db.StatOrgReposTop(db.ParseRequest(r))
respondWith(w, top)
}
func statOrgReposActivity(w http.ResponseWriter, r *http.Request) {
activity := db.StatOrgReposActivity(db.ParseRequest(r))
respondWith(w, activity)
}
func statOrgTeamsTop(w http.ResponseWriter, r *http.Request) {
top := db.StatOrgTeamsTop(db.ParseRequest(r))
respondWith(w, top)
}
func statOrgTeamsActivity(w http.ResponseWriter, r *http.Request) {
activity := db.StatOrgTeamsActivity(db.ParseRequest(r))
respondWith(w, activity)
}
func statOrgUsersTop(w http.ResponseWriter, r *http.Request) {
top := db.StatOrgUsersTop(db.ParseRequest(r))
respondWith(w, top)
}