317 lines
6.6 KiB
Go
317 lines
6.6 KiB
Go
package encoder
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/cortezaproject/corteza-server/compose/types"
|
|
)
|
|
|
|
type (
|
|
parsedTime struct {
|
|
field string
|
|
value string
|
|
}
|
|
)
|
|
|
|
// Time formatter
|
|
//
|
|
// Takes ptr to time.Time so we can conver both cases (value + ptr)
|
|
// The function also generates additional fields with included timezone.
|
|
func fmtTime(field string, tp *time.Time, tz string) (pt []*parsedTime, err error) {
|
|
if tp == nil {
|
|
return pt, nil
|
|
}
|
|
|
|
pt = append(pt, &parsedTime{
|
|
field: field,
|
|
value: tp.UTC().Format(time.RFC3339),
|
|
})
|
|
if tz == "" || tz == "UTC" {
|
|
return
|
|
}
|
|
|
|
loc, err := time.LoadLocation(tz)
|
|
if err != nil {
|
|
return pt, err
|
|
}
|
|
tt := tp.In(loc)
|
|
pt = append(pt,
|
|
&parsedTime{
|
|
field: field + "_date",
|
|
value: tt.Format("2006-01-02"),
|
|
}, &parsedTime{
|
|
field: field + "_time",
|
|
value: tt.Format("15:04:05"),
|
|
})
|
|
return
|
|
}
|
|
|
|
func fmtUint64(u uint64) string {
|
|
return strconv.FormatUint(u, 10)
|
|
}
|
|
|
|
func fmtSysUser(u uint64, finder userFinder) (string, error) {
|
|
if u <= 0 || finder == nil {
|
|
return fmtUint64(u), nil
|
|
}
|
|
su, err := finder(u)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
switch true {
|
|
case su.Name != "":
|
|
return su.Name, nil
|
|
case su.Handle != "":
|
|
return su.Handle, nil
|
|
case su.Email != "":
|
|
return su.Email, nil
|
|
case su.Username != "":
|
|
return su.Username, nil
|
|
}
|
|
|
|
return fmt.Sprintf("%d", su.ID), nil
|
|
}
|
|
|
|
func (enc flatWriter) Record(r *types.Record) (err error) {
|
|
var out = make([]string, len(enc.ff))
|
|
|
|
procTime := func(d []string, pts []*parsedTime, base int) {
|
|
for i, p := range pts {
|
|
d[base+i] = p.value
|
|
}
|
|
}
|
|
|
|
for f, field := range enc.ff {
|
|
switch field.name {
|
|
case "recordID", "ID":
|
|
out[f] = fmtUint64(r.ID)
|
|
case "moduleID":
|
|
out[f] = fmtUint64(r.ModuleID)
|
|
case "namespaceID":
|
|
out[f] = fmtUint64(r.NamespaceID)
|
|
case "ownedBy":
|
|
out[f], err = fmtSysUser(r.OwnedBy, enc.u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case "createdBy":
|
|
out[f], err = fmtSysUser(r.CreatedBy, enc.u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case "createdAt":
|
|
tt, err := fmtTime("createdAt", &r.CreatedAt, enc.tz)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
procTime(out, tt, f)
|
|
case "updatedBy":
|
|
out[f], err = fmtSysUser(r.UpdatedBy, enc.u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case "updatedAt":
|
|
tt, err := fmtTime("updatedAt", r.UpdatedAt, enc.tz)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
procTime(out, tt, f)
|
|
case "deletedBy":
|
|
out[f], err = fmtSysUser(r.DeletedBy, enc.u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case "deletedAt":
|
|
tt, err := fmtTime("deletedAt", r.DeletedAt, enc.tz)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
procTime(out, tt, f)
|
|
default:
|
|
vv := r.Values.FilterByName(field.name)
|
|
// @todo support for field.encodeAllMulti
|
|
if len(vv) > 0 {
|
|
out[f] = vv[0].Value
|
|
}
|
|
}
|
|
}
|
|
|
|
defer enc.w.Flush()
|
|
|
|
return enc.w.Write(out)
|
|
}
|
|
|
|
func (enc structuredEncoder) Record(r *types.Record) (err error) {
|
|
var (
|
|
// Exporter can choose fields so we need this buffer
|
|
// to hold just what we need
|
|
out = make(map[string]interface{})
|
|
vv types.RecordValueSet
|
|
c int
|
|
)
|
|
|
|
procTime := func(d map[string]interface{}, pts []*parsedTime) {
|
|
for _, p := range pts {
|
|
d[p.field] = p.value
|
|
}
|
|
}
|
|
|
|
for _, f := range enc.ff {
|
|
switch f.name {
|
|
case "recordID", "ID":
|
|
// encode all numbers as string (to prevent overflow of uint64 values)
|
|
out[f.name] = fmtUint64(r.ID)
|
|
case "moduleID":
|
|
// encode all numbers as string (to prevent overflow of uint64 values)
|
|
out[f.name] = fmtUint64(r.ModuleID)
|
|
case "namespaceID":
|
|
// encode all numbers as string (to prevent overflow of uint64 values)
|
|
out[f.name] = fmtUint64(r.NamespaceID)
|
|
case "ownedBy":
|
|
out[f.name], err = fmtSysUser(r.OwnedBy, enc.u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case "createdBy":
|
|
out[f.name], err = fmtSysUser(r.CreatedBy, enc.u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case "createdAt":
|
|
tt, err := fmtTime("createdAt", &r.CreatedAt, enc.tz)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
procTime(out, tt)
|
|
case "updatedBy":
|
|
out[f.name], err = fmtSysUser(r.UpdatedBy, enc.u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case "updatedAt":
|
|
if r.UpdatedAt == nil {
|
|
out[f.name] = nil
|
|
} else {
|
|
tt, err := fmtTime("updatedAt", r.UpdatedAt, enc.tz)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
procTime(out, tt)
|
|
}
|
|
|
|
case "deletedBy":
|
|
out[f.name], err = fmtSysUser(r.DeletedBy, enc.u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case "deletedAt":
|
|
if r.DeletedAt == nil {
|
|
out[f.name] = nil
|
|
} else {
|
|
tt, err := fmtTime("deletedAt", r.DeletedAt, enc.tz)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
procTime(out, tt)
|
|
}
|
|
|
|
default:
|
|
vv = r.Values.FilterByName(f.name)
|
|
c = len(vv)
|
|
|
|
if c == 0 {
|
|
break
|
|
}
|
|
|
|
if c == 1 {
|
|
out[f.name] = vv[0].Value
|
|
} else {
|
|
multi := make([]string, c)
|
|
|
|
for n := range vv {
|
|
multi[n] = vv[n].Value
|
|
}
|
|
|
|
out[f.name] = multi
|
|
}
|
|
}
|
|
}
|
|
|
|
return enc.w.Encode(out)
|
|
}
|
|
|
|
func (enc *excelizeEncoder) Record(r *types.Record) (err error) {
|
|
enc.row++
|
|
var u string
|
|
|
|
procTime := func(pts []*parsedTime, base int) {
|
|
for i, p := range pts {
|
|
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(base+i), p.value)
|
|
}
|
|
}
|
|
|
|
for p, f := range enc.ff {
|
|
p++
|
|
switch f.name {
|
|
case "recordID", "ID":
|
|
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(p), fmtUint64(r.ID))
|
|
case "moduleID":
|
|
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(p), fmtUint64(r.ModuleID))
|
|
case "namespaceID":
|
|
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(p), fmtUint64(r.NamespaceID))
|
|
case "ownedBy":
|
|
u, err = fmtSysUser(r.OwnedBy, enc.u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(p), u)
|
|
case "createdBy":
|
|
u, err = fmtSysUser(r.CreatedBy, enc.u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(p), u)
|
|
case "createdAt":
|
|
tt, err := fmtTime("createdAt", &r.CreatedAt, enc.tz)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
procTime(tt, p)
|
|
case "updatedBy":
|
|
u, err = fmtSysUser(r.UpdatedBy, enc.u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(p), u)
|
|
case "updatedAt":
|
|
tt, err := fmtTime("updatedAt", r.UpdatedAt, enc.tz)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
procTime(tt, p)
|
|
case "deletedBy":
|
|
u, err = fmtSysUser(r.DeletedBy, enc.u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(p), u)
|
|
case "deletedAt":
|
|
tt, err := fmtTime("deletedAt", r.DeletedAt, enc.tz)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
procTime(tt, p)
|
|
default:
|
|
vv := r.Values.FilterByName(f.name)
|
|
if len(vv) > 0 {
|
|
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(p), vv[0].Value)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|