diff --git a/pkg/database/incidents.sql.go b/pkg/database/incidents.sql.go index e814354..a49f5aa 100644 --- a/pkg/database/incidents.sql.go +++ b/pkg/database/incidents.sql.go @@ -250,8 +250,10 @@ SELECT i.start_time, i.end_time, i.location, - i.metadata + i.metadata, + COUNT(ic.incident_id) calls_count FROM incidents i +LEFT JOIN incidents_calls ic ON i.id = ic.incident_id WHERE CASE WHEN $1::TIMESTAMPTZ IS NOT NULL THEN i.start_time >= $1 ELSE TRUE END AND @@ -261,6 +263,7 @@ CASE WHEN $2::TIMESTAMPTZ IS NOT NULL THEN i.name ILIKE '%' || $3 || '%' OR i.description ILIKE '%' || $3 || '%' ) ELSE TRUE END) +GROUP BY i.id ORDER BY CASE WHEN $4::TEXT = 'asc' THEN i.start_time END ASC, CASE WHEN $4::TEXT = 'desc' THEN i.start_time END DESC @@ -277,7 +280,18 @@ type ListIncidentsPParams struct { PerPage int32 `json:"per_page"` } -func (q *Queries) ListIncidentsP(ctx context.Context, arg ListIncidentsPParams) ([]Incident, error) { +type ListIncidentsPRow struct { + ID uuid.UUID `json:"id"` + Name string `json:"name"` + Description *string `json:"description"` + StartTime pgtype.Timestamptz `json:"start_time"` + EndTime pgtype.Timestamptz `json:"end_time"` + Location []byte `json:"location"` + Metadata jsontypes.Metadata `json:"metadata"` + CallsCount int64 `json:"calls_count"` +} + +func (q *Queries) ListIncidentsP(ctx context.Context, arg ListIncidentsPParams) ([]ListIncidentsPRow, error) { rows, err := q.db.Query(ctx, listIncidentsP, arg.Start, arg.End, @@ -290,9 +304,9 @@ func (q *Queries) ListIncidentsP(ctx context.Context, arg ListIncidentsPParams) return nil, err } defer rows.Close() - var items []Incident + var items []ListIncidentsPRow for rows.Next() { - var i Incident + var i ListIncidentsPRow if err := rows.Scan( &i.ID, &i.Name, @@ -301,6 +315,7 @@ func (q *Queries) ListIncidentsP(ctx context.Context, arg ListIncidentsPParams) &i.EndTime, &i.Location, &i.Metadata, + &i.CallsCount, ); err != nil { return nil, err } diff --git a/pkg/database/mocks/Store.go b/pkg/database/mocks/Store.go index d7a0636..b308e41 100644 --- a/pkg/database/mocks/Store.go +++ b/pkg/database/mocks/Store.go @@ -2829,23 +2829,23 @@ func (_c *Store_ListIncidentsCount_Call) RunAndReturn(run func(context.Context, } // ListIncidentsP provides a mock function with given fields: ctx, arg -func (_m *Store) ListIncidentsP(ctx context.Context, arg database.ListIncidentsPParams) ([]database.Incident, error) { +func (_m *Store) ListIncidentsP(ctx context.Context, arg database.ListIncidentsPParams) ([]database.ListIncidentsPRow, error) { ret := _m.Called(ctx, arg) if len(ret) == 0 { panic("no return value specified for ListIncidentsP") } - var r0 []database.Incident + var r0 []database.ListIncidentsPRow var r1 error - if rf, ok := ret.Get(0).(func(context.Context, database.ListIncidentsPParams) ([]database.Incident, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, database.ListIncidentsPParams) ([]database.ListIncidentsPRow, error)); ok { return rf(ctx, arg) } - if rf, ok := ret.Get(0).(func(context.Context, database.ListIncidentsPParams) []database.Incident); ok { + if rf, ok := ret.Get(0).(func(context.Context, database.ListIncidentsPParams) []database.ListIncidentsPRow); ok { r0 = rf(ctx, arg) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]database.Incident) + r0 = ret.Get(0).([]database.ListIncidentsPRow) } } @@ -2877,12 +2877,12 @@ func (_c *Store_ListIncidentsP_Call) Run(run func(ctx context.Context, arg datab return _c } -func (_c *Store_ListIncidentsP_Call) Return(_a0 []database.Incident, _a1 error) *Store_ListIncidentsP_Call { +func (_c *Store_ListIncidentsP_Call) Return(_a0 []database.ListIncidentsPRow, _a1 error) *Store_ListIncidentsP_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *Store_ListIncidentsP_Call) RunAndReturn(run func(context.Context, database.ListIncidentsPParams) ([]database.Incident, error)) *Store_ListIncidentsP_Call { +func (_c *Store_ListIncidentsP_Call) RunAndReturn(run func(context.Context, database.ListIncidentsPParams) ([]database.ListIncidentsPRow, error)) *Store_ListIncidentsP_Call { _c.Call.Return(run) return _c } diff --git a/pkg/database/querier.go b/pkg/database/querier.go index 6bf2b20..f8f15e2 100644 --- a/pkg/database/querier.go +++ b/pkg/database/querier.go @@ -54,7 +54,7 @@ type Querier interface { ListCallsCount(ctx context.Context, arg ListCallsCountParams) (int64, error) ListCallsP(ctx context.Context, arg ListCallsPParams) ([]ListCallsPRow, error) ListIncidentsCount(ctx context.Context, start pgtype.Timestamptz, end pgtype.Timestamptz, filter *string) (int64, error) - ListIncidentsP(ctx context.Context, arg ListIncidentsPParams) ([]Incident, error) + ListIncidentsP(ctx context.Context, arg ListIncidentsPParams) ([]ListIncidentsPRow, error) RemoveFromIncident(ctx context.Context, iD uuid.UUID, callIds []uuid.UUID) error RestoreTalkgroupVersion(ctx context.Context, versionIds int) (Talkgroup, error) SetAppPrefs(ctx context.Context, appName string, prefs []byte, uid int) error diff --git a/pkg/incidents/incstore/store.go b/pkg/incidents/incstore/store.go index 3f42396..79785ed 100644 --- a/pkg/incidents/incstore/store.go +++ b/pkg/incidents/incstore/store.go @@ -35,7 +35,7 @@ type Store interface { UpdateNotes(ctx context.Context, incidentID uuid.UUID, callID uuid.UUID, notes []byte) error // Incidents gets incidents matching parameters and pagination. - Incidents(ctx context.Context, p IncidentsParams) (incs []incidents.Incident, totalCount int, err error) + Incidents(ctx context.Context, p IncidentsParams) (incs []Incident, totalCount int, err error) // Incident gets a single incident. Incident(ctx context.Context, id uuid.UUID) (*incidents.Incident, error) @@ -152,7 +152,7 @@ func (s *store) AddRemoveIncidentCalls(ctx context.Context, incidentID uuid.UUID }, pgx.TxOptions{}) } -func (s *store) Incidents(ctx context.Context, p IncidentsParams) (incs []incidents.Incident, totalCount int, err error) { +func (s *store) Incidents(ctx context.Context, p IncidentsParams) (incs []Incident, totalCount int, err error) { db := database.FromCtx(ctx) offset, perPage := p.Pagination.OffsetPerPage(100) @@ -166,7 +166,7 @@ func (s *store) Incidents(ctx context.Context, p IncidentsParams) (incs []incide } var count int64 - var rows []database.Incident + var rows []database.ListIncidentsPRow txErr := db.InTx(ctx, func(db database.Store) error { var err error count, err = db.ListIncidentsCount(ctx, dbParam.Start, dbParam.End, dbParam.Filter) @@ -185,9 +185,9 @@ func (s *store) Incidents(ctx context.Context, p IncidentsParams) (incs []incide return nil, 0, txErr } - incs = make([]incidents.Incident, 0, len(rows)) + incs = make([]Incident, 0, len(rows)) for _, v := range rows { - incs = append(incs, fromDBIncident(v.ID, v)) + incs = append(incs, fromDBListInPRow(v.ID, v)) } return incs, int(count), err @@ -204,6 +204,26 @@ func fromDBIncident(id uuid.UUID, d database.Incident) incidents.Incident { } } +type Incident struct { + incidents.Incident + + CallCount int `json:"callCount"` +} + +func fromDBListInPRow(id uuid.UUID, d database.ListIncidentsPRow) Incident { + return Incident{ + Incident: incidents.Incident{ + ID: id, + Name: d.Name, + Description: d.Description, + StartTime: jsontypes.TimePtrFromTSTZ(d.StartTime), + EndTime: jsontypes.TimePtrFromTSTZ(d.EndTime), + Metadata: d.Metadata, + }, + CallCount: int(d.CallsCount), + } +} + func fromDBCalls(d []database.GetIncidentCallsRow) []incidents.IncidentCall { r := make([]incidents.IncidentCall, 0, len(d)) for _, v := range d { diff --git a/pkg/rest/incidents.go b/pkg/rest/incidents.go index 10b115b..b586345 100644 --- a/pkg/rest/incidents.go +++ b/pkg/rest/incidents.go @@ -55,7 +55,7 @@ func (ia *incidentsAPI) listIncidents(w http.ResponseWriter, r *http.Request) { } res := struct { - Incidents []incidents.Incident `json:"incidents"` + Incidents []incstore.Incident `json:"incidents"` Count int `json:"count"` }{} diff --git a/sql/postgres/queries/incidents.sql b/sql/postgres/queries/incidents.sql index 97c1fb9..16dde5c 100644 --- a/sql/postgres/queries/incidents.sql +++ b/sql/postgres/queries/incidents.sql @@ -58,8 +58,10 @@ SELECT i.start_time, i.end_time, i.location, - i.metadata + i.metadata, + COUNT(ic.incident_id) calls_count FROM incidents i +LEFT JOIN incidents_calls ic ON i.id = ic.incident_id WHERE CASE WHEN sqlc.narg('start')::TIMESTAMPTZ IS NOT NULL THEN i.start_time >= sqlc.narg('start') ELSE TRUE END AND @@ -69,6 +71,7 @@ CASE WHEN sqlc.narg('end')::TIMESTAMPTZ IS NOT NULL THEN i.name ILIKE '%' || @filter || '%' OR i.description ILIKE '%' || @filter || '%' ) ELSE TRUE END) +GROUP BY i.id ORDER BY CASE WHEN @direction::TEXT = 'asc' THEN i.start_time END ASC, CASE WHEN @direction::TEXT = 'desc' THEN i.start_time END DESC