<commit_before>package handler

import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"

	"github.com/oursky/ourd/asset"
	"github.com/oursky/ourd/hook"
	"github.com/oursky/ourd/oddb"
	"github.com/oursky/ourd/oddb/oddbconv"
	"github.com/oursky/ourd/oderr"
	"github.com/oursky/ourd/router"
)

type serializedRecord struct {
	Record     *oddb.Record
	AssetStore asset.Store
}

func newSerializedRecord(record *oddb.Record, assetStore asset.Store) serializedRecord {
	return serializedRecord{record, assetStore}
}

func (s serializedRecord) MarshalJSON() ([]byte, error) {
	r := s.Record

	m := map[string]interface{}{}
	m["_id"] = s.Record.ID.String()
	m["_type"] = "record"

	if !s.Record.CreatedAt.IsZero() {
		m["_created_at"] = s.Record.CreatedAt
	}
	if s.Record.CreatorID != "" {
		m["_created_by"] = s.Record.CreatorID
	}
	if !s.Record.UpdatedAt.IsZero() {
		m["_updated_at"] = s.Record.UpdatedAt
	}
	if s.Record.UpdaterID != "" {
		m["_updated_by"] = s.Record.UpdaterID
	}

	for key, value := range r.Data {
		switch v := value.(type) {
		case time.Time:
			m[key] = oddbconv.ToMap(oddbconv.MapTime(v))
		case oddb.Reference:
			m[key] = oddbconv.ToMap(oddbconv.MapReference(v))
		case *oddb.Location:
			m[key] = oddbconv.ToMap((*oddbconv.MapLocation)(v))
		case oddb.Asset:
			// TODO: refactor out this if. We know whether we are
			// injected an asset store at the start of handler
			var url string
			if signer, ok := s.AssetStore.(asset.URLSigner); ok {
				url = signer.SignedURL(v.Name, time.Now().Add(15*time.Minute))
			} else {
				url = ""
			}
			m[key] = struct {
				Type string `json:"$type"`
				Name string `json:"$name"`
				URL  string `json:"$url,omitempty"`
			}{"asset", v.Name, url}
		default:
			m[key] = v
		}
	}

	if r.OwnerID != "" {
		m["_ownerID"] = r.OwnerID
	}
	m["_access"] = r.ACL

	transient := map[string]interface{}{}
	for key, value := range r.Transient {
		switch v := value.(type) {
		case oddb.Record:
			transient[key] = newSerializedRecord(&v, s.AssetStore)
		default:
			transient[key] = v
		}
	}
	if len(transient) > 0 {
		m["_transient"] = transient
	}

	return json.Marshal(m)
}

// transportRecord override JSON serialization and deserialization of
// oddb.Record
type transportRecord oddb.Record

func (r *transportRecord) UnmarshalJSON(data []byte) error {
	object := map[string]interface{}{}
	err := json.Unmarshal(data, &object)

	if err != nil {
		return err<commit_msg>handler: reduce cyclomatic complexity of serializedRecord<commit_after>package handler

import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strings"
	"time"

	log "github.com/Sirupsen/logrus"

	"github.com/oursky/ourd/asset"
	"github.com/oursky/ourd/hook"
	"github.com/oursky/ourd/oddb"
	"github.com/oursky/ourd/oddb/oddbconv"
	"github.com/oursky/ourd/oderr"
	"github.com/oursky/ourd/router"
)

type serializedRecord struct {
	Record     *oddb.Record
	AssetStore asset.Store
}

func newSerializedRecord(record *oddb.Record, assetStore asset.Store) serializedRecord {
	return serializedRecord{record, assetStore}
}

func (s serializedRecord) MarshalJSON() ([]byte, error) {
	r := s.Record

	m := map[string]interface{}{}
	m["_id"] = s.Record.ID.String()
	m["_type"] = "record"
	m["_access"] = r.ACL

	if r.OwnerID != "" {
		m["_ownerID"] = r.OwnerID
	}
	if !r.CreatedAt.IsZero() {
		m["_created_at"] = r.CreatedAt
	}
	if r.CreatorID != "" {
		m["_created_by"] = r.CreatorID
	}
	if !r.UpdatedAt.IsZero() {
		m["_updated_at"] = r.UpdatedAt
	}
	if r.UpdaterID != "" {
		m["_updated_by"] = r.UpdaterID
	}

	for key, value := range r.Data {
		switch v := value.(type) {
		case time.Time:
			m[key] = oddbconv.ToMap(oddbconv.MapTime(v))
		case oddb.Reference:
			m[key] = oddbconv.ToMap(oddbconv.MapReference(v))
		case *oddb.Location:
			m[key] = oddbconv.ToMap((*oddbconv.MapLocation)(v))
		case oddb.Asset:
			// TODO: refactor out this if. We know whether we are
			// injected an asset store at the start of handler
			var url string
			if signer, ok := s.AssetStore.(asset.URLSigner); ok {
				url = signer.SignedURL(v.Name, time.Now().Add(15*time.Minute))
			} else {
				url = ""
			}
			m[key] = struct {
				Type string `json:"$type"`
				Name string `json:"$name"`
				URL  string `json:"$url,omitempty"`
			}{"asset", v.Name, url}
		default:
			m[key] = v
		}
	}

	transient := s.marshalTransient(r.Transient)
	if len(transient) > 0 {
		m["_transient"] = transient
	}

	return json.Marshal(m)
}

func (s serializedRecord) marshalTransient(transient map[string]interface{}) map[string]interface{} {
	m := map[string]interface{}{}
	for key, value := range transient {
		switch v := value.(type) {
		case oddb.Record:
			m[key] = newSerializedRecord(&v, s.AssetStore)
		default:
			m[key] = v
		}
	}
	return m
}

// transportRecord override JSON serialization and deserialization of
// oddb.Record
type transportRecord oddb.Record

func (r *transportRecord) UnmarshalJSON(data []byte) error {
	object := map[string]interface{}{}
	err := json.Unmarshal(data, &object)

	if err != nil {
		return err
{'fraction_non_alphanumeric': 0.15853658536585366, 'fraction_numerical': 0.0011801730920535012, 'mean_word_length': 3.797169811320755, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5157352', 'n_tokens_mistral': 2085, 'n_tokens_neox': 1934, 'n_words': 398}