mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2025-11-13 18:03:53 +00:00
Added content-range headers
This commit is contained in:
parent
3eb17666bf
commit
faafe5abea
13
pkg/common/reflection_utils.go
Normal file
13
pkg/common/reflection_utils.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
func Len(v any) int {
|
||||||
|
val := reflect.ValueOf(v)
|
||||||
|
switch val.Kind() {
|
||||||
|
case reflect.Slice, reflect.Array, reflect.Map, reflect.String, reflect.Chan:
|
||||||
|
return val.Len()
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,6 +18,11 @@ type RequestOptions struct {
|
|||||||
CustomOperators []CustomOperator `json:"customOperators"`
|
CustomOperators []CustomOperator `json:"customOperators"`
|
||||||
ComputedColumns []ComputedColumn `json:"computedColumns"`
|
ComputedColumns []ComputedColumn `json:"computedColumns"`
|
||||||
Parameters []Parameter `json:"parameters"`
|
Parameters []Parameter `json:"parameters"`
|
||||||
|
|
||||||
|
// Cursor pagination
|
||||||
|
CursorForward string `json:"cursor_forward"`
|
||||||
|
CursorBackward string `json:"cursor_backward"`
|
||||||
|
FetchRowNumber *string `json:"fetch_row_number"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Parameter struct {
|
type Parameter struct {
|
||||||
@ -68,6 +73,7 @@ type Response struct {
|
|||||||
|
|
||||||
type Metadata struct {
|
type Metadata struct {
|
||||||
Total int64 `json:"total"`
|
Total int64 `json:"total"`
|
||||||
|
Count int64 `json:"count"`
|
||||||
Filtered int64 `json:"filtered"`
|
Filtered int64 `json:"filtered"`
|
||||||
Limit int `json:"limit"`
|
Limit int `json:"limit"`
|
||||||
Offset int `json:"offset"`
|
Offset int `json:"offset"`
|
||||||
|
|||||||
@ -31,7 +31,9 @@ func (opts *ExtendedRequestOptions) GetCursorFilter(
|
|||||||
modelColumns []string, // optional: for validation
|
modelColumns []string, // optional: for validation
|
||||||
expandJoins map[string]string, // optional: alias → JOIN SQL
|
expandJoins map[string]string, // optional: alias → JOIN SQL
|
||||||
) (string, error) {
|
) (string, error) {
|
||||||
|
if strings.Contains(tableName, ".") {
|
||||||
|
tableName = strings.SplitN(tableName, ".", 2)[1]
|
||||||
|
}
|
||||||
// --------------------------------------------------------------------- //
|
// --------------------------------------------------------------------- //
|
||||||
// 1. Determine active cursor
|
// 1. Determine active cursor
|
||||||
// --------------------------------------------------------------------- //
|
// --------------------------------------------------------------------- //
|
||||||
@ -137,11 +139,11 @@ func (opts *ExtendedRequestOptions) GetCursorFilter(
|
|||||||
// ------------------------------------------------------------------------- //
|
// ------------------------------------------------------------------------- //
|
||||||
// Helper: get active cursor (forward or backward)
|
// Helper: get active cursor (forward or backward)
|
||||||
func (opts *ExtendedRequestOptions) getActiveCursor() (id string, direction CursorDirection) {
|
func (opts *ExtendedRequestOptions) getActiveCursor() (id string, direction CursorDirection) {
|
||||||
if opts.CursorForward != "" {
|
if opts.RequestOptions.CursorForward != "" {
|
||||||
return opts.CursorForward, CursorForward
|
return opts.RequestOptions.CursorForward, CursorForward
|
||||||
}
|
}
|
||||||
if opts.CursorBackward != "" {
|
if opts.RequestOptions.CursorBackward != "" {
|
||||||
return opts.CursorBackward, CursorBackward
|
return opts.RequestOptions.CursorBackward, CursorBackward
|
||||||
}
|
}
|
||||||
return "", 0
|
return "", 0
|
||||||
}
|
}
|
||||||
|
|||||||
@ -339,7 +339,7 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply cursor-based pagination
|
// Apply cursor-based pagination
|
||||||
if len(options.CursorForward) > 0 || len(options.CursorBackward) > 0 {
|
if len(options.RequestOptions.CursorForward) > 0 || len(options.RequestOptions.CursorBackward) > 0 {
|
||||||
logger.Debug("Applying cursor pagination")
|
logger.Debug("Applying cursor pagination")
|
||||||
|
|
||||||
// Get primary key name
|
// Get primary key name
|
||||||
@ -389,6 +389,7 @@ func (h *Handler) handleRead(ctx context.Context, w common.ResponseWriter, id st
|
|||||||
|
|
||||||
metadata := &common.Metadata{
|
metadata := &common.Metadata{
|
||||||
Total: int64(total),
|
Total: int64(total),
|
||||||
|
Count: int64(common.Len(modelPtr)),
|
||||||
Filtered: int64(total),
|
Filtered: int64(total),
|
||||||
Limit: limit,
|
Limit: limit,
|
||||||
Offset: offset,
|
Offset: offset,
|
||||||
@ -937,7 +938,12 @@ func (h *Handler) sendFormattedResponse(w common.ResponseWriter, data interface{
|
|||||||
if options.CleanJSON {
|
if options.CleanJSON {
|
||||||
data = h.cleanJSON(data)
|
data = h.cleanJSON(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.SetHeader("Content-Type", "application/json")
|
w.SetHeader("Content-Type", "application/json")
|
||||||
|
w.SetHeader("Content-Range", fmt.Sprintf("%d-%d/%d", metadata.Offset, int64(metadata.Offset)+metadata.Count, metadata.Filtered))
|
||||||
|
w.SetHeader("X-Api-Range-Total", fmt.Sprintf("%d", metadata.Filtered))
|
||||||
|
w.SetHeader("X-Api-Range-Size", fmt.Sprintf("%d", metadata.Count))
|
||||||
|
|
||||||
// Format response based on response format option
|
// Format response based on response format option
|
||||||
switch options.ResponseFormat {
|
switch options.ResponseFormat {
|
||||||
case "simple":
|
case "simple":
|
||||||
|
|||||||
@ -33,7 +33,6 @@ type ExtendedRequestOptions struct {
|
|||||||
Distinct bool
|
Distinct bool
|
||||||
SkipCount bool
|
SkipCount bool
|
||||||
SkipCache bool
|
SkipCache bool
|
||||||
FetchRowNumber *string
|
|
||||||
PKRow *string
|
PKRow *string
|
||||||
|
|
||||||
// Response format
|
// Response format
|
||||||
@ -41,10 +40,6 @@ type ExtendedRequestOptions struct {
|
|||||||
|
|
||||||
// Transaction
|
// Transaction
|
||||||
AtomicTransaction bool
|
AtomicTransaction bool
|
||||||
|
|
||||||
// Cursor pagination
|
|
||||||
CursorForward string
|
|
||||||
CursorBackward string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExpandOption represents a relation expansion configuration
|
// ExpandOption represents a relation expansion configuration
|
||||||
@ -171,9 +166,9 @@ func (h *Handler) parseOptionsFromHeaders(r common.Request) ExtendedRequestOptio
|
|||||||
options.Offset = &offset
|
options.Offset = &offset
|
||||||
}
|
}
|
||||||
case strings.HasPrefix(normalizedKey, "x-cursor-forward"):
|
case strings.HasPrefix(normalizedKey, "x-cursor-forward"):
|
||||||
options.CursorForward = decodedValue
|
options.RequestOptions.CursorForward = decodedValue
|
||||||
case strings.HasPrefix(normalizedKey, "x-cursor-backward"):
|
case strings.HasPrefix(normalizedKey, "x-cursor-backward"):
|
||||||
options.CursorBackward = decodedValue
|
options.RequestOptions.CursorBackward = decodedValue
|
||||||
|
|
||||||
// Advanced Features
|
// Advanced Features
|
||||||
case strings.HasPrefix(normalizedKey, "x-advsql-"):
|
case strings.HasPrefix(normalizedKey, "x-advsql-"):
|
||||||
@ -189,7 +184,7 @@ func (h *Handler) parseOptionsFromHeaders(r common.Request) ExtendedRequestOptio
|
|||||||
case strings.HasPrefix(normalizedKey, "x-skipcache"):
|
case strings.HasPrefix(normalizedKey, "x-skipcache"):
|
||||||
options.SkipCache = strings.ToLower(decodedValue) == "true"
|
options.SkipCache = strings.ToLower(decodedValue) == "true"
|
||||||
case strings.HasPrefix(normalizedKey, "x-fetch-rownumber"):
|
case strings.HasPrefix(normalizedKey, "x-fetch-rownumber"):
|
||||||
options.FetchRowNumber = &decodedValue
|
options.RequestOptions.FetchRowNumber = &decodedValue
|
||||||
case strings.HasPrefix(normalizedKey, "x-pkrow"):
|
case strings.HasPrefix(normalizedKey, "x-pkrow"):
|
||||||
options.PKRow = &decodedValue
|
options.PKRow = &decodedValue
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user