Only get the latest 10 trap collections
Otherwise the page gets really swamped
This commit is contained in:
parent
d3b9d34bd2
commit
b7318ae973
12 changed files with 304 additions and 27 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -4,3 +4,6 @@
|
||||||
[submodule "go-geojson2h3"]
|
[submodule "go-geojson2h3"]
|
||||||
path = go-geojson2h3
|
path = go-geojson2h3
|
||||||
url = git@github.com:Gleipnir-Technology/go-geojson2h3.git
|
url = git@github.com:Gleipnir-Technology/go-geojson2h3.git
|
||||||
|
[submodule "bob"]
|
||||||
|
path = bob
|
||||||
|
url = git@github.com:Gleipnir-Technology/bob.git
|
||||||
|
|
|
||||||
1
bob
Submodule
1
bob
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 96da65fd88a50ae532079e8ea69746183f4af3a1
|
||||||
10
database.go
10
database.go
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"embed"
|
"embed"
|
||||||
|
|
@ -197,12 +196,3 @@ func updateSummaryTables(ctx context.Context, org *models.Organization) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertQueryToString(query bob.BaseQuery[*dialect.InsertQuery]) string {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
_, err := query.WriteQuery(context.TODO(), buf, 0)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Sprintf("Failed to write query: %v", err)
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
|
||||||
60
html.go
60
html.go
|
|
@ -512,6 +512,9 @@ func htmlSource(w http.ResponseWriter, r *http.Request, user *models.User, id st
|
||||||
}
|
}
|
||||||
cadence, deltas := calculateCadenceVariance(treatment_times)
|
cadence, deltas := calculateCadenceVariance(treatment_times)
|
||||||
for i, treatment := range treatments {
|
for i, treatment := range treatments {
|
||||||
|
if i >= len(deltas) {
|
||||||
|
break
|
||||||
|
}
|
||||||
treatment.CadenceDelta = deltas[i]
|
treatment.CadenceDelta = deltas[i]
|
||||||
treatments[i] = treatment
|
treatments[i] = treatment
|
||||||
}
|
}
|
||||||
|
|
@ -782,12 +785,57 @@ func trapsBySource(ctx context.Context, org *models.Organization, sourceID strin
|
||||||
location_ids = append(location_ids, location.TrapLocationGlobalid)
|
location_ids = append(location_ids, location.TrapLocationGlobalid)
|
||||||
args = append(args, psql.Arg(location.TrapLocationGlobalid))
|
args = append(args, psql.Arg(location.TrapLocationGlobalid))
|
||||||
}
|
}
|
||||||
trap_data, err := org.FSTrapdata(
|
/*
|
||||||
sm.Where(
|
trap_data, err := org.FSTrapdata(
|
||||||
models.FSTrapdata.Columns.LocID.In(args...),
|
sm.Where(
|
||||||
),
|
models.FSTrapdata.Columns.LocID.In(args...),
|
||||||
sm.OrderBy("enddatetime"),
|
),
|
||||||
).All(ctx, PGInstance.BobDB)
|
sm.OrderBy("enddatetime"),
|
||||||
|
).All(ctx, PGInstance.BobDB)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
query := org.FSTrapdata(
|
||||||
|
sm.From(
|
||||||
|
psql.Select(
|
||||||
|
sm.From(psql.F("ROW_NUMBER")(
|
||||||
|
fm.Over(
|
||||||
|
wm.PartitionBy(models.FSTrapdata.Columns.LocID),
|
||||||
|
wm.OrderBy(models.FSTrapdata.Columns.Enddatetime).Desc(),
|
||||||
|
),
|
||||||
|
)).As("row_num"),
|
||||||
|
sm.Where(models.FSTrapdata.Columns.LocID.In(args...))),
|
||||||
|
),
|
||||||
|
sm.Where(psql.Quote("row_num").LTE(psql.Arg(10))),
|
||||||
|
sm.OrderBy(models.FSTrapdata.Columns.LocID),
|
||||||
|
sm.OrderBy(models.FSTrapdata.Columns.Enddatetime).Desc(),
|
||||||
|
)
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
query := psql.Select(
|
||||||
|
sm.From(
|
||||||
|
psql.Select(
|
||||||
|
sm.Columns(
|
||||||
|
models.FSTrapdata.Columns.Globalid,
|
||||||
|
psql.F("ROW_NUMBER")(
|
||||||
|
fm.Over(
|
||||||
|
wm.PartitionBy(models.FSTrapdata.Columns.LocID),
|
||||||
|
wm.OrderBy(models.FSTrapdata.Columns.Enddatetime).Desc(),
|
||||||
|
),
|
||||||
|
).As("row_num"),
|
||||||
|
sm.From(models.FSTrapdata.Name()),
|
||||||
|
),
|
||||||
|
sm.Where(models.FSTrapdata.Columns.LocID.In(args...))),
|
||||||
|
),
|
||||||
|
sm.Where(psql.Quote("row_num").LTE(psql.Arg(10))),
|
||||||
|
sm.OrderBy(models.FSTrapdata.Columns.LocID),
|
||||||
|
sm.OrderBy(models.FSTrapdata.Columns.Enddatetime).Desc(),
|
||||||
|
)
|
||||||
|
log.Info().Str("trapdata", queryToString(query)).Msg("Getting trap data")
|
||||||
|
trap_data, err := query.Exec(ctx, PGInstance.BobDB)
|
||||||
|
*/
|
||||||
|
|
||||||
|
trap_data, err := sql.TrapDataByLocationIDRecent(org.ID, location_ids).All(ctx, PGInstance.BobDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to query trap data: %w", err)
|
return nil, fmt.Errorf("Failed to query trap data: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ type Treatment struct {
|
||||||
Product string
|
Product string
|
||||||
}
|
}
|
||||||
|
|
||||||
func toTemplateTraps(locations []sql.TrapLocationBySourceIDRow, trap_data models.FSTrapdatumSlice, counts []sql.TrapCountByLocationIDRow) ([]TrapNearby, error) {
|
func toTemplateTraps(locations []sql.TrapLocationBySourceIDRow, trap_data []sql.TrapDataByLocationIDRecentRow, counts []sql.TrapCountByLocationIDRow) ([]TrapNearby, error) {
|
||||||
results := make([]TrapNearby, 0)
|
results := make([]TrapNearby, 0)
|
||||||
count_by_trap_data_id := make(map[string]*sql.TrapCountByLocationIDRow)
|
count_by_trap_data_id := make(map[string]*sql.TrapCountByLocationIDRow)
|
||||||
for _, c := range counts {
|
for _, c := range counts {
|
||||||
|
|
@ -174,12 +174,9 @@ func toTemplateTraps(locations []sql.TrapLocationBySourceIDRow, trap_data models
|
||||||
if !ok {
|
if !ok {
|
||||||
return results, errors.New(fmt.Sprintf("Failed to find trap count for %s", td.Globalid))
|
return results, errors.New(fmt.Sprintf("Failed to find trap count for %s", td.Globalid))
|
||||||
}
|
}
|
||||||
if td.LocID.IsNull() {
|
loc_id := td.LocID
|
||||||
return results, errors.New("Got a trap data with no location ID")
|
|
||||||
}
|
|
||||||
loc_id := td.LocID.MustGet()
|
|
||||||
count := &TrapCount{
|
count := &TrapCount{
|
||||||
Ended: fsToTime(td.Enddatetime),
|
Ended: time.UnixMilli(td.Enddatetime),
|
||||||
Females: int(c.TotalFemales.IntPart()),
|
Females: int(c.TotalFemales.IntPart()),
|
||||||
ID: td.Globalid,
|
ID: td.Globalid,
|
||||||
Males: int(c.TotalMales),
|
Males: int(c.TotalMales),
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import (
|
||||||
//go:embed trapcount_by_location_id.bob.sql
|
//go:embed trapcount_by_location_id.bob.sql
|
||||||
var formattedQueries_trapcount_by_location_id string
|
var formattedQueries_trapcount_by_location_id string
|
||||||
|
|
||||||
var trapCountByLocationIDSQL = formattedQueries_trapcount_by_location_id[159:580]
|
var trapCountByLocationIDSQL = formattedQueries_trapcount_by_location_id[159:591]
|
||||||
|
|
||||||
type TrapCountByLocationIDQuery = orm.ModQuery[*dialect.SelectQuery, trapCountByLocationID, TrapCountByLocationIDRow, []TrapCountByLocationIDRow, trapCountByLocationIDTransformer]
|
type TrapCountByLocationIDQuery = orm.ModQuery[*dialect.SelectQuery, trapCountByLocationID, TrapCountByLocationIDRow, []TrapCountByLocationIDRow, trapCountByLocationIDTransformer]
|
||||||
|
|
||||||
|
|
@ -59,7 +59,7 @@ func TrapCountByLocationID(OrganizationID int32, LocID []string) *TrapCountByLoc
|
||||||
q.AppendSelect(expressionTypArgs.subExpr(12, 223))
|
q.AppendSelect(expressionTypArgs.subExpr(12, 223))
|
||||||
q.SetTable(expressionTypArgs.subExpr(234, 318))
|
q.SetTable(expressionTypArgs.subExpr(234, 318))
|
||||||
q.AppendWhere(expressionTypArgs.subExpr(330, 379))
|
q.AppendWhere(expressionTypArgs.subExpr(330, 379))
|
||||||
q.AppendGroup(expressionTypArgs.subExpr(394, 421))
|
q.AppendGroup(expressionTypArgs.subExpr(394, 432))
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,4 +16,4 @@ WHERE
|
||||||
td.organization_id = $1
|
td.organization_id = $1
|
||||||
AND td.loc_id IN ($2)
|
AND td.loc_id IN ($2)
|
||||||
GROUP BY
|
GROUP BY
|
||||||
td.globalid, td.enddatetime;
|
td.globalid, td.loc_id, td.enddatetime;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
-- TrapCountByLocationID
|
-- TrapCountByLocationID
|
||||||
SELECT
|
SELECT
|
||||||
td.loc_id AS trapdata_globalid,
|
td.globalid AS trapdata_globalid,
|
||||||
td.enddatetime AS trapdata_enddate,
|
td.enddatetime AS trapdata_enddate,
|
||||||
COALESCE(SUM(sa.females), 0) AS total_females,
|
COALESCE(SUM(sa.females), 0) AS total_females,
|
||||||
COALESCE(SUM(sa.males), 0) AS total_males,
|
COALESCE(SUM(sa.males), 0) AS total_males,
|
||||||
|
|
@ -13,5 +13,5 @@ WHERE
|
||||||
td.organization_id = $1
|
td.organization_id = $1
|
||||||
AND td.loc_id IN ($2)
|
AND td.loc_id IN ($2)
|
||||||
GROUP BY
|
GROUP BY
|
||||||
td.globalid, td.enddatetime;
|
td.globalid, td.loc_id, td.enddatetime;
|
||||||
|
|
||||||
|
|
|
||||||
108
sql/trapdata_by_location_id_recent.bob.go
Normal file
108
sql/trapdata_by_location_id_recent.bob.go
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
// Code generated by BobGen psql v0.41.1. DO NOT EDIT.
|
||||||
|
// This file is meant to be re-generated in place and/or deleted at any time.
|
||||||
|
|
||||||
|
package sql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
_ "embed"
|
||||||
|
"io"
|
||||||
|
"iter"
|
||||||
|
|
||||||
|
"github.com/stephenafamo/bob"
|
||||||
|
"github.com/stephenafamo/bob/dialect/psql"
|
||||||
|
"github.com/stephenafamo/bob/dialect/psql/dialect"
|
||||||
|
"github.com/stephenafamo/bob/expr"
|
||||||
|
"github.com/stephenafamo/bob/orm"
|
||||||
|
"github.com/stephenafamo/scan"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed trapdata_by_location_id_recent.bob.sql
|
||||||
|
var formattedQueries_trapdata_by_location_id_recent string
|
||||||
|
|
||||||
|
var trapDataByLocationIDRecentSQL = formattedQueries_trapdata_by_location_id_recent[164:454]
|
||||||
|
|
||||||
|
type TrapDataByLocationIDRecentQuery = orm.ModQuery[*dialect.SelectQuery, trapDataByLocationIDRecent, TrapDataByLocationIDRecentRow, []TrapDataByLocationIDRecentRow, trapDataByLocationIDRecentTransformer]
|
||||||
|
|
||||||
|
func TrapDataByLocationIDRecent(OrganizationID int32, LocID []string) *TrapDataByLocationIDRecentQuery {
|
||||||
|
var expressionTypArgs trapDataByLocationIDRecent
|
||||||
|
|
||||||
|
expressionTypArgs.OrganizationID = psql.Arg(OrganizationID)
|
||||||
|
expressionTypArgs.LocID = expr.ToArgs(LocID...)
|
||||||
|
|
||||||
|
return &TrapDataByLocationIDRecentQuery{
|
||||||
|
Query: orm.Query[trapDataByLocationIDRecent, TrapDataByLocationIDRecentRow, []TrapDataByLocationIDRecentRow, trapDataByLocationIDRecentTransformer]{
|
||||||
|
ExecQuery: orm.ExecQuery[trapDataByLocationIDRecent]{
|
||||||
|
BaseQuery: bob.BaseQuery[trapDataByLocationIDRecent]{
|
||||||
|
Expression: expressionTypArgs,
|
||||||
|
Dialect: dialect.Dialect,
|
||||||
|
QueryType: bob.QueryTypeSelect,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Scanner: func(context.Context, []string) (func(*scan.Row) (any, error), func(any) (TrapDataByLocationIDRecentRow, error)) {
|
||||||
|
return func(row *scan.Row) (any, error) {
|
||||||
|
var t TrapDataByLocationIDRecentRow
|
||||||
|
row.ScheduleScanByIndex(0, &t.Enddatetime)
|
||||||
|
row.ScheduleScanByIndex(1, &t.Globalid)
|
||||||
|
row.ScheduleScanByIndex(2, &t.LocID)
|
||||||
|
return &t, nil
|
||||||
|
}, func(v any) (TrapDataByLocationIDRecentRow, error) {
|
||||||
|
return *(v.(*TrapDataByLocationIDRecentRow)), nil
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Mod: bob.ModFunc[*dialect.SelectQuery](func(q *dialect.SelectQuery) {
|
||||||
|
q.AppendSelect(expressionTypArgs.subExpr(7, 36))
|
||||||
|
q.SetTable(expressionTypArgs.subExpr(42, 244))
|
||||||
|
q.AppendWhere(expressionTypArgs.subExpr(251, 264))
|
||||||
|
q.CombinedOrder.AppendOrder(expressionTypArgs.subExpr(274, 290))
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TrapDataByLocationIDRecentRow = struct {
|
||||||
|
Enddatetime int64 `db:"enddatetime"`
|
||||||
|
Globalid string `db:"globalid"`
|
||||||
|
LocID string `db:"loc_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type trapDataByLocationIDRecentTransformer = bob.SliceTransformer[TrapDataByLocationIDRecentRow, []TrapDataByLocationIDRecentRow]
|
||||||
|
|
||||||
|
type trapDataByLocationIDRecent struct {
|
||||||
|
OrganizationID bob.Expression
|
||||||
|
LocID bob.Expression
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o trapDataByLocationIDRecent) args() iter.Seq[orm.ArgWithPosition] {
|
||||||
|
return func(yield func(arg orm.ArgWithPosition) bool) {
|
||||||
|
if !yield(orm.ArgWithPosition{
|
||||||
|
Name: "organizationID",
|
||||||
|
Start: 207,
|
||||||
|
Stop: 209,
|
||||||
|
Expression: o.OrganizationID,
|
||||||
|
}) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !yield(orm.ArgWithPosition{
|
||||||
|
Name: "locID",
|
||||||
|
Start: 227,
|
||||||
|
Stop: 229,
|
||||||
|
Expression: o.LocID,
|
||||||
|
}) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o trapDataByLocationIDRecent) raw(from, to int) string {
|
||||||
|
return trapDataByLocationIDRecentSQL[from:to]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o trapDataByLocationIDRecent) subExpr(from, to int) bob.Expression {
|
||||||
|
return orm.ArgsToExpression(trapDataByLocationIDRecentSQL, from, to, o.args())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o trapDataByLocationIDRecent) WriteSQL(ctx context.Context, w io.Writer, d bob.Dialect, start int) ([]any, error) {
|
||||||
|
return o.subExpr(0, len(trapDataByLocationIDRecentSQL)).WriteSQL(ctx, w, d, start)
|
||||||
|
}
|
||||||
15
sql/trapdata_by_location_id_recent.bob.sql
Normal file
15
sql/trapdata_by_location_id_recent.bob.sql
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
-- Code generated by BobGen psql v0.41.1. DO NOT EDIT.
|
||||||
|
-- This file is meant to be re-generated in place and/or deleted at any time.
|
||||||
|
|
||||||
|
-- TrapDataByLocationIDRecent
|
||||||
|
SELECT enddatetime, globalid, loc_id
|
||||||
|
FROM (
|
||||||
|
SELECT enddatetime, globalid, loc_id, ROW_NUMBER()
|
||||||
|
OVER (PARTITION BY loc_id ORDER BY enddatetime DESC) as row_num
|
||||||
|
FROM fs_trapdata
|
||||||
|
WHERE
|
||||||
|
organization_id = $1 AND
|
||||||
|
loc_id IN ($2)
|
||||||
|
) ranked_data
|
||||||
|
WHERE row_num <= 10
|
||||||
|
ORDER BY enddatetime DESC;
|
||||||
103
sql/trapdata_by_location_id_recent.bob_test.go
Normal file
103
sql/trapdata_by_location_id_recent.bob_test.go
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
// Code generated by BobGen psql v0.41.1. DO NOT EDIT.
|
||||||
|
// This file is meant to be re-generated in place and/or deleted at any time.
|
||||||
|
|
||||||
|
package sql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/stephenafamo/bob"
|
||||||
|
"github.com/stephenafamo/bob/dialect/psql"
|
||||||
|
testutils "github.com/stephenafamo/bob/test/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTrapDataByLocationIDRecent(t *testing.T) {
|
||||||
|
t.Run("Base", func(t *testing.T) {
|
||||||
|
var sb strings.Builder
|
||||||
|
|
||||||
|
query := TrapDataByLocationIDRecent(random_int32(nil), []string{random_string(nil)})
|
||||||
|
|
||||||
|
if _, err := query.WriteQuery(t.Context(), &sb, 1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmp.Diff(trapDataByLocationIDRecentSQL, sb.String()); diff != "" {
|
||||||
|
t.Fatalf("unexpected result (-got +want):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Mod", func(t *testing.T) {
|
||||||
|
var sb strings.Builder
|
||||||
|
|
||||||
|
query := TrapDataByLocationIDRecent(random_int32(nil), []string{random_string(nil)})
|
||||||
|
|
||||||
|
if _, err := psql.Select(query).WriteQuery(t.Context(), &sb, 1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
queryDiff, err := testutils.QueryDiff(trapDataByLocationIDRecentSQL, sb.String(), formatQuery)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if queryDiff != "" {
|
||||||
|
fmt.Println(sb.String())
|
||||||
|
t.Fatalf("unexpected result (-got +want):\n%s", queryDiff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Scanning", func(t *testing.T) {
|
||||||
|
if testDB == nil {
|
||||||
|
t.Skip("skipping test, no DSN provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxTx, cancel := context.WithCancel(t.Context())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
tx, err := testDB.Begin(ctxTx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error starting transaction: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := tx.Rollback(ctxTx); err != nil {
|
||||||
|
t.Fatalf("Error rolling back transaction: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
query, args, err := bob.Build(ctxTx, psql.Select(TrapDataByLocationIDRecent(random_int32(nil), []string{random_string(nil)})))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := tx.QueryContext(ctxTx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
columns, err := rows.Columns()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(columns) != 3 {
|
||||||
|
t.Fatalf("expected %d columns, got %d", 3, len(columns))
|
||||||
|
}
|
||||||
|
|
||||||
|
if columns[0] != "enddatetime" {
|
||||||
|
t.Fatalf("expected column %d to be %s, got %s", 0, "enddatetime", columns[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if columns[1] != "globalid" {
|
||||||
|
t.Fatalf("expected column %d to be %s, got %s", 1, "globalid", columns[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if columns[2] != "loc_id" {
|
||||||
|
t.Fatalf("expected column %d to be %s, got %s", 2, "loc_id", columns[2])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
12
sql/trapdata_by_location_id_recent.sql
Normal file
12
sql/trapdata_by_location_id_recent.sql
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
-- TrapDataByLocationIDRecent
|
||||||
|
SELECT enddatetime, globalid, loc_id
|
||||||
|
FROM (
|
||||||
|
SELECT enddatetime, globalid, loc_id, ROW_NUMBER()
|
||||||
|
OVER (PARTITION BY loc_id ORDER BY enddatetime DESC) as row_num
|
||||||
|
FROM fs_trapdata
|
||||||
|
WHERE
|
||||||
|
organization_id = $1 AND
|
||||||
|
loc_id IN ($2)
|
||||||
|
) ranked_data
|
||||||
|
WHERE row_num <= 10
|
||||||
|
ORDER BY enddatetime DESC;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue