fix: Ensure accurate Total Count and correct Limit=0 handling
This commit finalizes the complex querying logic: - **Refactor `GetAll` (sqlite.go):** Reworks the internal logic to ensure the total number of matching records (`totalCount`) is calculated via a separate COUNT query *before* applying LIMIT/OFFSET. - **Corrected Pagination:** Adds an explicit check in `GetAll` to return an empty `items` list when `limit=0`, while still reporting the correct `totalCount`. - **API Handler Update:** Consumes the accurate `totalCount` returned by the Store layer and includes it in the final API response under the `totalItems` field.
This commit is contained in:
parent
4704d7802b
commit
07cdb55411
|
|
@ -1,3 +1,4 @@
|
||||||
|
// upupa_dataist_ir/internal/api/handlers.go
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -108,7 +109,7 @@ func (a *API) GetAllRecordsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
offset = 0
|
offset = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
records, err := a.Records.GetAll(collection.ID, finalFilters, orderBy, limit, offset)
|
records, totalItems, err := a.Records.GetAll(collection.ID, finalFilters, orderBy, limit, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error retrieving records: %v", err)
|
log.Printf("Error retrieving records: %v", err)
|
||||||
http.Error(w, "Failed to retrieve records", http.StatusInternalServerError)
|
http.Error(w, "Failed to retrieve records", http.StatusInternalServerError)
|
||||||
|
|
@ -120,7 +121,7 @@ func (a *API) GetAllRecordsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
response := map[string]interface{}{
|
response := map[string]interface{}{
|
||||||
"items": records,
|
"items": records,
|
||||||
"totalItems": len(records),
|
"totalItems": totalItems,
|
||||||
"limit": limit,
|
"limit": limit,
|
||||||
"offset": offset,
|
"offset": offset,
|
||||||
"orderBy": orderBy,
|
"orderBy": orderBy,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// internal/store/repository.go
|
// internal/store/repository
|
||||||
package store
|
package store
|
||||||
|
|
||||||
import "upupa_dataist_ir/pkg/models"
|
import "upupa_dataist_ir/pkg/models"
|
||||||
|
|
@ -10,9 +10,7 @@ type CollectionRepository interface {
|
||||||
|
|
||||||
type RecordRepository interface {
|
type RecordRepository interface {
|
||||||
CreateRecord(r models.Record) (models.Record, error)
|
CreateRecord(r models.Record) (models.Record, error)
|
||||||
|
GetAll(collectionID string, filters map[string]interface{}, orderBy string, limit, offset int) ([]models.Record, int, error)
|
||||||
GetAll(collectionID string, filters map[string]interface{}, orderBy string, limit, offset int) ([]models.Record, error)
|
|
||||||
|
|
||||||
GetByID(collectionID, recordID string) (models.Record, error)
|
GetByID(collectionID, recordID string) (models.Record, error)
|
||||||
Update(r models.Record) error
|
Update(r models.Record) error
|
||||||
Delete(collectionID, recordID string) error
|
Delete(collectionID, recordID string) error
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
// upupa_dataist_ir/internal/store/sqlite.go
|
||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -96,15 +97,14 @@ func (s *SQLiteStore) CreateRecord(r models.Record) (models.Record, error) {
|
||||||
return s.GetByID(r.CollectionID, r.ID)
|
return s.GetByID(r.CollectionID, r.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SQLiteStore) GetAll(collectionID string, filters map[string]interface{}, orderBy string, limit, offset int) ([]models.Record, error) {
|
func (s *SQLiteStore) GetAll(collectionID string, filters map[string]interface{}, orderBy string, limit, offset int) ([]models.Record, int, error) {
|
||||||
|
|
||||||
baseQuery := `SELECT id, collection_id, created, updated, data FROM records WHERE collection_id = ?`
|
baseQuery := `SELECT id, collection_id, created, updated, data FROM records WHERE collection_id = ?`
|
||||||
|
|
||||||
args := []interface{}{collectionID}
|
args := []interface{}{collectionID}
|
||||||
|
|
||||||
if len(filters) > 0 {
|
|
||||||
filterClause := ""
|
filterClause := ""
|
||||||
|
if len(filters) > 0 {
|
||||||
for key, value := range filters {
|
for key, value := range filters {
|
||||||
field, op, err := parseFilterKey(key)
|
field, op, err := parseFilterKey(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -117,9 +117,20 @@ func (s *SQLiteStore) GetAll(collectionID string, filters map[string]interface{}
|
||||||
filterClause += fmt.Sprintf(" AND %s %s ?", caster, op)
|
filterClause += fmt.Sprintf(" AND %s %s ?", caster, op)
|
||||||
args = append(args, value)
|
args = append(args, value)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
countQuery := "SELECT COUNT(*) FROM records WHERE collection_id = ?" + filterClause
|
||||||
|
var totalCount int
|
||||||
|
err := s.db.QueryRow(countQuery, args...).Scan(&totalCount)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if limit == 0 {
|
||||||
|
return []models.Record{}, totalCount, nil
|
||||||
|
}
|
||||||
|
|
||||||
baseQuery += filterClause
|
baseQuery += filterClause
|
||||||
}
|
|
||||||
|
|
||||||
sortClause := " ORDER BY created DESC"
|
sortClause := " ORDER BY created DESC"
|
||||||
if orderBy != "" {
|
if orderBy != "" {
|
||||||
|
|
@ -127,13 +138,11 @@ func (s *SQLiteStore) GetAll(collectionID string, filters map[string]interface{}
|
||||||
}
|
}
|
||||||
baseQuery += sortClause
|
baseQuery += sortClause
|
||||||
|
|
||||||
if limit > 0 {
|
|
||||||
baseQuery += fmt.Sprintf(" LIMIT %d OFFSET %d", limit, offset)
|
baseQuery += fmt.Sprintf(" LIMIT %d OFFSET %d", limit, offset)
|
||||||
}
|
|
||||||
|
|
||||||
rows, err := s.db.Query(baseQuery, args...)
|
rows, err := s.db.Query(baseQuery, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
|
|
@ -147,12 +156,12 @@ func (s *SQLiteStore) GetAll(collectionID string, filters map[string]interface{}
|
||||||
|
|
||||||
err := rows.Scan(&r.ID, &r.CollectionID, &r.Created, &r.Updated, &dataStr)
|
err := rows.Scan(&r.ID, &r.CollectionID, &r.Created, &r.Updated, &dataStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := unmarshalRecordData(dataStr)
|
data, err := unmarshalRecordData(dataStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Data = data
|
r.Data = data
|
||||||
|
|
@ -160,10 +169,10 @@ func (s *SQLiteStore) GetAll(collectionID string, filters map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
return nil, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return records, nil
|
return records, totalCount, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SQLiteStore) GetByID(collectionID, recordID string) (models.Record, error) {
|
func (s *SQLiteStore) GetByID(collectionID, recordID string) (models.Record, error) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue