diff --git a/octosql/values.go b/octosql/values.go index 1e54c31d..f6b35d46 100644 --- a/octosql/values.go +++ b/octosql/values.go @@ -424,8 +424,6 @@ func (value Value) append(builder *strings.Builder) { } func (value Value) ToRawGoValue(t Type) interface{} { - // TODO: Add complex types. - // TODO: Fix union handling. switch value.TypeID { case TypeIDNull: return nil diff --git a/outputs/formats/csv_format.go b/outputs/formats/csv_format.go index 762cd910..147b34e2 100644 --- a/outputs/formats/csv_format.go +++ b/outputs/formats/csv_format.go @@ -4,6 +4,9 @@ import ( "encoding/csv" "fmt" "io" + "strconv" + "strings" + "time" "github.com/cube2222/octosql/octosql" "github.com/cube2222/octosql/physical" @@ -33,13 +36,36 @@ func (t *CSVFormatter) SetSchema(schema physical.Schema) { } func (t *CSVFormatter) Write(values []octosql.Value) error { + var builder strings.Builder row := make([]string, len(values)) for i := range values { - row[i] = fmt.Sprintf("%v", values[i].ToRawGoValue(t.fields[i].Type)) + FormatCSVValue(&builder, values[i]) + row[i] = builder.String() + builder.Reset() } return t.writer.Write(row) } +func FormatCSVValue(builder *strings.Builder, value octosql.Value) { + switch value.TypeID { + case octosql.TypeIDNull: + case octosql.TypeIDInt: + builder.WriteString(strconv.FormatInt(int64(value.Int), 10)) + case octosql.TypeIDFloat: + builder.WriteString(strconv.FormatFloat(value.Float, 'f', -1, 64)) + case octosql.TypeIDBoolean: + builder.WriteString(strconv.FormatBool(value.Boolean)) + case octosql.TypeIDString: + builder.WriteString(value.Str) + case octosql.TypeIDTime: + builder.WriteString(value.Time.Format(time.RFC3339)) + case octosql.TypeIDDuration: + builder.WriteString(fmt.Sprint(value.Duration)) + default: + panic("invalid value type to print in CSV: " + value.TypeID.String()) + } +} + func (t *CSVFormatter) Close() error { t.writer.Flush() return nil diff --git a/tests/scenarios/outputs/csv/types.err b/tests/scenarios/outputs/csv/types.err new file mode 100644 index 00000000..e69de29b diff --git a/tests/scenarios/outputs/csv/types.in b/tests/scenarios/outputs/csv/types.in new file mode 100644 index 00000000..55e96c9d --- /dev/null +++ b/tests/scenarios/outputs/csv/types.in @@ -0,0 +1,6 @@ +octosql "SELECT 42, + 42.42, 42.42424242424242, float(42), + true, false, + null, + 'test' as hello, + INTERVAL 5 HOURS + INTERVAL 32 MINUTES + INTERVAL 42 SECONDS" -ocsv diff --git a/tests/scenarios/outputs/csv/types.out b/tests/scenarios/outputs/csv/types.out new file mode 100644 index 00000000..c5cd3c92 --- /dev/null +++ b/tests/scenarios/outputs/csv/types.out @@ -0,0 +1,2 @@ +col_0,col_1,col_2,col_3,col_4,col_5,col_6,hello,col_8 +42,42.42,42.42424242424242,42,true,false,,test,5h32m42s