pkg/jsonapi/data.go
Rama master · réplica de lectura del repositorio original.
package jsonapi
import (
"encoding/json"
"github.com/cozy/cozy-stack/pkg/couchdb"
)
// Object is an interface to serialize something to a JSON-API Object
type Object interface {
couchdb.Doc
Links() *LinksList
Relationships() RelationshipMap
Included() []Object
}
// Meta is a container for the couchdb revision and the total number of items,
// in JSON-API land
type Meta struct {
Rev string `json:"rev,omitempty"`
Warning string `json:"warning,omitempty"`
Count *int `json:"count,omitempty"`
FileID string `json:"file_id,omitempty"`
ExecutionStats *couchdb.ExecutionStats `json:"execution_stats,omitempty"`
}
// LinksList is the common links used in JSON-API for the top-level or a
// resource object
// See http://jsonapi.org/format/#document-links
type LinksList struct {
Self string `json:"self,omitempty"`
Related string `json:"related,omitempty"`
Prev string `json:"prev,omitempty"`
Next string `json:"next,omitempty"`
Icon string `json:"icon,omitempty"`
Perms string `json:"permissions,omitempty"`
Webhook string `json:"webhook,omitempty"`
// Thumbnails
Tiny string `json:"tiny,omitempty"`
Small string `json:"small,omitempty"`
Medium string `json:"medium,omitempty"`
Large string `json:"large,omitempty"`
}
// Relationship is a resource linkage, as described in JSON-API
// See http://jsonapi.org/format/#document-resource-object-relationships
//
// Data can be a single ResourceIdentifier for to-one relationships,
// or an array of them for to-many relationships.
type Relationship struct {
Links *LinksList `json:"links,omitempty"`
Meta *Meta `json:"meta,omitempty"`
Data interface{} `json:"data"`
}
// ResourceIdentifier returns the resource identifier of the relationship.
func (r *Relationship) ResourceIdentifier() (*couchdb.DocReference, bool) {
if m, ok := r.Data.(map[string]interface{}); ok {
idd, _ := m["id"].(string)
typ, _ := m["type"].(string)
return &couchdb.DocReference{ID: idd, Type: typ}, true
}
return nil, false
}
// RelationshipMap is a map of relationships
// See http://jsonapi.org/format/#document-resource-object-relationships
type RelationshipMap map[string]Relationship
// Clone returns a copy of the relationship map. Relationship data decoded from
// JSON is cloned recursively.
func (r RelationshipMap) Clone() RelationshipMap {
if r == nil {
return nil
}
cloned := make(RelationshipMap, len(r))
for name, relationship := range r {
if data, ok := relationship.Data.(map[string]interface{}); ok {
relationship.Data = couchdb.CloneJSONMap(data)
}
cloned[name] = relationship
}
return cloned
}
// ObjectMarshalling is a JSON-API object
// See http://jsonapi.org/format/#document-resource-objects
type ObjectMarshalling struct {
Type string `json:"type"`
ID string `json:"id"`
Attributes *json.RawMessage `json:"attributes"`
Meta Meta `json:"meta"`
Links *LinksList `json:"links,omitempty"`
Relationships RelationshipMap `json:"relationships,omitempty"`
}
// GetRelationship returns the relationship with the given name from
// the relationships map.
func (o *ObjectMarshalling) GetRelationship(name string) (*Relationship, bool) {
rel, ok := o.Relationships[name]
if !ok {
return nil, false
}
return &rel, true
}
// MarshalObject serializes an Object to JSON.
// It returns a json.RawMessage that can be used a in Document.
func MarshalObject(o Object) (json.RawMessage, error) {
id := o.ID()
rev := o.Rev()
links := o.Links()
rels := o.Relationships()
o.SetID("")
o.SetRev("")
defer func() {
o.SetID(id)
o.SetRev(rev)
}()
b, err := json.Marshal(o)
if err != nil {
return nil, err
}
data := ObjectMarshalling{
Type: o.DocType(),
ID: id,
Attributes: (*json.RawMessage)(&b),
Meta: Meta{Rev: rev},
Links: links,
Relationships: rels,
}
return json.Marshal(data)
}