adding sequence marker to get topics to support staggard loading

This commit is contained in:
Roland Osborne 2022-07-03 00:18:57 -07:00
parent e4830093e3
commit 1c05180251
2 changed files with 128 additions and 9 deletions

View File

@ -2485,7 +2485,7 @@ paths:
get: get:
tags: tags:
- content - content
description: Get channel topic slots. If revision set, detail fields omitted in response description: Get channel topic slots. If revision set, detail fields omitted in response. Staggered loading supported through sequnce marker. Initially count can be used to limit the topics returned. The sequence marker returned in the header must be used in subsequent queries for the same topic window.
operationId: get-channel-topics operationId: get-channel-topics
security: security:
- bearerAuth: [] - bearerAuth: []
@ -2501,16 +2501,43 @@ paths:
description: return updated topics since revision description: return updated topics since revision
required: false required: false
schema: schema:
type: string type: integer
format: int64
- name: count
in: query
description: limit number of topics from latest when revision not set
required: false
schema:
type: integer
format: int64
- name: begin
in: query
description: return topics after and including sequence marker
required: false
schema:
type: integer
format: int64
- name: end
in: query
description: return topics before and not including sequence marker
required: false
schema:
type: integer
format: int64
responses: responses:
'200': '200':
description: successful operation description: successful operation
headers: headers:
X-Topic-Revision: Topic-Revision:
schema: schema:
type: integer type: integer
format: int64 format: int64
description: current topic revision description: current topic revision
Topic-Marker:
schema:
type: integer
format: int64
description: sequnce marker of first topic when count set
content: content:
application/json: application/json:
schema: schema:

View File

@ -6,9 +6,23 @@ import (
"databag/internal/store" "databag/internal/store"
) )
func reverse(input []store.TopicSlot) []store.TopicSlot {
var output []store.TopicSlot
for i := len(input) - 1; i >= 0; i-- {
output = append(output, input[i])
}
return output
}
func GetChannelTopics(w http.ResponseWriter, r *http.Request) { func GetChannelTopics(w http.ResponseWriter, r *http.Request) {
var revisionSet bool var revisionSet bool
var revision int64 var revision int64
var beginSet bool
var begin int64
var endSet bool
var end int64
var countSet bool
var count int
channelSlot, _, err, code := getChannelSlot(r, false) channelSlot, _, err, code := getChannelSlot(r, false)
if err != nil { if err != nil {
@ -25,24 +39,102 @@ func GetChannelTopics(w http.ResponseWriter, r *http.Request) {
} }
} }
cnt := r.FormValue("count")
if cnt != "" {
countSet = true
if count, err = strconv.Atoi(cnt); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
}
bn := r.FormValue("begin")
if bn != "" {
beginSet = true
if begin, err = strconv.ParseInt(bn, 10, 64); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
}
en := r.FormValue("end")
if en != "" {
endSet = true
if end, err = strconv.ParseInt(en, 10, 64); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
}
response := []*Topic{} response := []*Topic{}
if revisionSet { if revisionSet {
var slots []store.TopicSlot var slots []store.TopicSlot
if err := store.DB.Preload("Topic").Where("channel_id = ? AND revision > ?", channelSlot.Channel.ID, revision).Find(&slots).Error; err != nil { if beginSet && !endSet {
ErrResponse(w, http.StatusInternalServerError, err) if err := store.DB.Preload("Topic").Where("channel_id = ? AND revision > ? AND id >= ?", channelSlot.Channel.ID, revision, begin).Find(&slots).Error; err != nil {
return ErrResponse(w, http.StatusInternalServerError, err)
return
}
} else if !beginSet && endSet {
if err := store.DB.Preload("Topic").Where("channel_id = ? AND revision > ? AND id < ?", channelSlot.Channel.ID, revision, end).Find(&slots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
} else if beginSet && endSet {
if err := store.DB.Preload("Topic").Where("channel_id = ? AND revision > ? AND id >= ? AND id < ?", channelSlot.Channel.ID, revision, begin, end).Find(&slots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
} else {
if err := store.DB.Preload("Topic").Where("channel_id = ? AND revision > ?", channelSlot.Channel.ID, revision).Find(&slots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
} }
for _, slot := range slots { for _, slot := range slots {
response = append(response, getTopicRevisionModel(&slot)) response = append(response, getTopicRevisionModel(&slot))
} }
} else { } else {
var slots []store.TopicSlot var slots []store.TopicSlot
if err := store.DB.Preload("Topic.Assets").Where("channel_id = ?", channelSlot.Channel.ID).Find(&slots).Error; err != nil { if countSet {
ErrResponse(w, http.StatusInternalServerError, err) if !endSet {
return if err := store.DB.Preload("Topic.Assets").Where("channel_id = ?", channelSlot.Channel.ID).Order("id desc").Limit(count).Find(&slots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
} else {
if err := store.DB.Preload("Topic.Assets").Where("channel_id = ? AND id < ?", channelSlot.Channel.ID, end).Order("id desc").Limit(count).Find(&slots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
}
slots = reverse(slots)
} else if beginSet && !endSet {
if err := store.DB.Preload("Topic.Assets").Where("channel_id = ? AND id >= ?", channelSlot.Channel.ID, begin).Find(&slots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
} else if !beginSet && endSet {
if err := store.DB.Preload("Topic.Assets").Where("channel_id = ? AND id < ?", channelSlot.Channel.ID, end).Find(&slots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
} else if beginSet && endSet {
if err := store.DB.Preload("Topic.Assets").Where("channel_id = ? AND id >= ? AND id < ?", channelSlot.Channel.ID, begin, end).Find(&slots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
} else {
if err := store.DB.Preload("Topic.Assets").Where("channel_id = ?", channelSlot.Channel.ID).Find(&slots).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
} }
for _, slot := range slots { for _, slot := range slots {
if slot.Topic != nil { if slot.Topic != nil {
if countSet {
w.Header().Set("Topic-Index", strconv.FormatUint(uint64(slot.ID), 10))
countSet = false
}
response = append(response, getTopicModel(&slot)) response = append(response, getTopicModel(&slot))
} }
} }