~evanj/cms

2171152d07759a25fa315df4321c09ead16f83e7 — Evan M Jones 4 months ago 81dac61 wip/cache/listicles
WIP
3 files changed, 100 insertions(+), 3 deletions(-)

M TODO
M internal/s/cache/content.go
M internal/s/db/content.go
M TODO => TODO +3 -3
@@ 1,9 1,9 @@
vet image and file uploads
payment option for users who use official site
payment options for commercial use
testing: 100% happy path and 80% total
documentation
controllers in one directory
cache lists
Go API move from evanjon.es and augment
Depth option on APIs
NOT NULL on varchar
no zero length varchar
goatcounter

M internal/s/cache/content.go => internal/s/cache/content.go +65 -0
@@ 1,6 1,7 @@
package cache

import (
	"encoding/json"
	"errors"
	"fmt"



@@ 99,4 100,68 @@ func (c *Cache) ContentDelete(space space.Space, ct contenttype.ContentType, ite
	return c.mc.Delete(key)
}

func (c *Cache) ContentPerContentType(space space.Space, ct contenttype.ContentType, before int, order db.OrderType, sortField string) (content.ContentList, error) {
	// Check if in cache.
	// Put into cache.
	// Put individual items in cache, pointing to list cache for invalidation.

	var (
		cl     db.ContentList
		key    = fmt.Sprintf("content::list::%s::%s::%s::%d::%s::%s", c.baseKey, space.ID(), ct.ID(), before, order.Val(), sortField)
		getter = func() (interface{}, error) {
			list, err := c.db.ContentPerContentType(space, ct, before, order, sortField)

			for _, content := range list.List() {
				cKey := fmt.Sprintf("content::list::item::%s::%s::%s", c.baseKey, space.ID(), content.ID())
				if err := c.updateContentCacheList(key, cKey, content); err != nil {
					return nil, err
				}
			}

			return list, err
		}
	)

	// TODO: Change to true.
	err := c.cache(true, key, &cl, getter)
	return &cl, err
}

func (c *Cache) updateContentCacheList(key, cKey string, content content.Content) error {
	// TODO: Loop through referenced items.

	// for _, v := range content.Values() {
	// 	switch v.Type() {
	// 	case valuetype.Reference:
	// 		break
	// 	case valuetype.ReferenceList:
	// 		break
	// 	}
	// }

	var listref struct{ Keys []string }
	it, err := c.mc.Get(cKey)
	if err == nil {
		// Item already in cache, hydrate value.
		c.log.Println("cache value being hydrated")

		if err := json.Unmarshal(it.Value, &listref); err != nil {
			c.log.Println("cache value corrupted")
			return err
		}
	}

	// Create/update value in cache.
	listref.Keys = append(listref.Keys, key)

	bytes, err := json.Marshal(listref)
	if err != nil {
		c.log.Println("cache value failed to marshal")
		return err
	}

	c.log.Println("cache value set")
	return c.mc.Set(&memcache.Item{Key: cKey, Value: bytes})
}

// TODO: ContentPerContentType

M internal/s/db/content.go => internal/s/db/content.go +32 -0
@@ 23,6 23,8 @@ var (
	OrderDesc OrderType = OrderType{val: "DESC"}
)

func (ot OrderType) Val() string { return ot.val }

func orderTypeReverse(o OrderType) OrderType {
	switch o {
	case OrderAsc:


@@ 1316,6 1318,12 @@ type ContentList struct {
	ContentListBefore int
}

type contentListJSON struct {
	ContentList       []*Content
	ContentListMore   bool
	ContentListBefore int
}

func newContentList(list []content.Content, hasMore bool, last int) *ContentList {
	return &ContentList{list, hasMore, last}
}


@@ 1323,3 1331,27 @@ func newContentList(list []content.Content, hasMore bool, last int) *ContentList
func (cl *ContentList) List() []content.Content { return cl.ContentList }
func (cl *ContentList) More() bool              { return cl.ContentListMore }
func (cl *ContentList) Before() int             { return cl.ContentListBefore }

func (cl *ContentList) MarshalJSON() ([]byte, error) {
	var r contentListJSON
	r.ContentListBefore = cl.ContentListBefore
	r.ContentListMore = cl.ContentListMore
	for _, c := range cl.ContentList {
		r.ContentList = append(r.ContentList, c.(*Content))
	}
	return json.Marshal(r)
}
func (cl *ContentList) UnmarshalJSON(b []byte) error {
	var r contentListJSON
	if err := json.Unmarshal(b, &r); err != nil {
		return err
	}

	cl.ContentListBefore = r.ContentListBefore
	cl.ContentListMore = r.ContentListMore
	for _, c := range r.ContentList {
		cl.ContentList = append(cl.ContentList, c)
	}

	return nil
}