Add support for timezone export

This commit is contained in:
Tomaž Jerman
2020-06-23 10:12:51 +02:00
parent 3b15dbc350
commit e0b0944921
7 changed files with 172 additions and 21 deletions
+33 -4
View File
@@ -27,12 +27,14 @@ type (
w FlatWriter
ff []field
u userFinder
tz string
}
structuredEncoder struct {
w StructuredEncoder
ff []field
u userFinder
tz string
}
)
@@ -49,15 +51,40 @@ func MakeFields(nn ...string) []field {
return ff
}
func preprocessHeader(hh []field, tz string) []field {
nhh := make([]field, 0)
// We need to prepare additional header fields for exporting
if tz != "" && tz != "UTC" {
for _, f := range hh {
switch f.name {
case "createdAt",
"updatedAt",
"deletedAt":
nhh = append(nhh, f, field{name: f.name + "_date"}, field{name: f.name + "_time"})
break
default:
nhh = append(nhh, f)
break
}
}
} else {
return hh
}
return nhh
}
func MultiValueField(name string) field {
return field{name: name, encodeAllMulti: true}
}
func NewFlatWriter(w FlatWriter, header bool, u userFinder, ff ...field) *flatWriter {
func NewFlatWriter(w FlatWriter, header bool, u userFinder, tz string, ff ...field) *flatWriter {
f := &flatWriter{
w: w,
ff: ff,
ff: preprocessHeader(ff, tz),
u: u,
tz: tz,
}
if header {
@@ -80,11 +107,13 @@ func (enc flatWriter) writeHeader() {
_ = enc.w.Write(ss)
}
func NewStructuredEncoder(w StructuredEncoder, u userFinder, ff ...field) *structuredEncoder {
func NewStructuredEncoder(w StructuredEncoder, u userFinder, tz string, ff ...field) *structuredEncoder {
return &structuredEncoder{
w: w,
w: w,
// No need for additional timezone headers, since the output is structured
ff: ff,
u: u,
tz: tz,
}
}
+4 -2
View File
@@ -13,15 +13,17 @@ type (
w io.Writer
ff []field
u userFinder
tz string
}
)
func NewExcelizeEncoder(w io.Writer, header bool, u userFinder, ff ...field) *excelizeEncoder {
func NewExcelizeEncoder(w io.Writer, header bool, u userFinder, tz string, ff ...field) *excelizeEncoder {
enc := &excelizeEncoder{
f: excelize.NewFile(),
w: w,
ff: ff,
ff: preprocessHeader(ff, tz),
u: u,
tz: tz,
}
if header {
+95 -12
View File
@@ -8,15 +8,44 @@ import (
"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)
func fmtTime(tp *time.Time) string {
// 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 ""
return pt, nil
}
return tp.UTC().Format(time.RFC3339)
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 {
@@ -49,6 +78,12 @@ func fmtSysUser(u uint64, finder userFinder) (string, error) {
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":
@@ -68,21 +103,33 @@ func (enc flatWriter) Record(r *types.Record) (err error) {
return err
}
case "createdAt":
out[f] = fmtTime(&r.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":
out[f] = fmtTime(r.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":
out[f] = fmtTime(r.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
@@ -106,6 +153,12 @@ func (enc structuredEncoder) Record(r *types.Record) (err error) {
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":
@@ -128,7 +181,11 @@ func (enc structuredEncoder) Record(r *types.Record) (err error) {
return err
}
case "createdAt":
out[f.name] = fmtTime(&r.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 {
@@ -138,7 +195,11 @@ func (enc structuredEncoder) Record(r *types.Record) (err error) {
if r.UpdatedAt == nil {
out[f.name] = nil
} else {
out[f.name] = fmtTime(r.UpdatedAt)
tt, err := fmtTime("updatedAt", r.UpdatedAt, enc.tz)
if err != nil {
return err
}
procTime(out, tt)
}
case "deletedBy":
@@ -150,7 +211,11 @@ func (enc structuredEncoder) Record(r *types.Record) (err error) {
if r.DeletedAt == nil {
out[f.name] = nil
} else {
out[f.name] = fmtTime(r.DeletedAt)
tt, err := fmtTime("deletedAt", r.DeletedAt, enc.tz)
if err != nil {
return err
}
procTime(out, tt)
}
default:
@@ -182,6 +247,12 @@ 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 {
@@ -204,7 +275,11 @@ func (enc *excelizeEncoder) Record(r *types.Record) (err error) {
}
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(p), u)
case "createdAt":
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(p), fmtTime(&r.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 {
@@ -212,7 +287,11 @@ func (enc *excelizeEncoder) Record(r *types.Record) (err error) {
}
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(p), u)
case "updatedAt":
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(p), fmtTime(r.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 {
@@ -220,7 +299,11 @@ func (enc *excelizeEncoder) Record(r *types.Record) (err error) {
}
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(p), u)
case "deletedAt":
_ = enc.f.SetCellStr(enc.sheet(), enc.pos(p), fmtTime(r.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 {