Skip to content

Commit

Permalink
add support for time fields
Browse files Browse the repository at this point in the history
  • Loading branch information
tlarsendataguy committed Jul 26, 2023
1 parent 209191b commit 264eb53
Show file tree
Hide file tree
Showing 11 changed files with 88 additions and 23 deletions.
7 changes: 7 additions & 0 deletions sdk/editing_recordinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ func (i *EditingRecordInfo) AddDateTimeField(name string, source string, options
return i.addField(name, `DateTime`, source, 19, 0, options...)
}

func (i *EditingRecordInfo) AddTimeField(name string, source string, options ...AddFieldOptionSetter) string {
return i.addField(name, `Time`, source, 8, 0, options...)
}

func (i *EditingRecordInfo) addField(name string, typeName string, source string, size int, scale int, options ...AddFieldOptionSetter) string {
addFieldOptions := AddFieldOptions{}
for _, setter := range options {
Expand Down Expand Up @@ -175,6 +179,9 @@ func (i *EditingRecordInfo) GenerateOutgoingRecordInfo() *OutgoingRecordInfo {
case `DateTime`:
outgoing = NewDateTimeField(field.Name, field.Source)()
info.DateTimeFields[field.Name] = outgoing
case `Time`:
outgoing = NewTimeField(field.Name, field.Source)()
info.DateTimeFields[field.Name] = outgoing
case `String`:
outgoing = NewStringField(field.Name, field.Source, field.Size)()
info.StringFields[field.Name] = outgoing
Expand Down
13 changes: 12 additions & 1 deletion sdk/import_file/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

const dateFormat = `2006-01-02`
const dateTimeFormat = `2006-01-02 15:04:05`
const timeFormat = `15:04:05`

type Extractor struct {
fields []b.FieldBase
Expand Down Expand Up @@ -52,7 +53,7 @@ func NewExtractor(fieldNameBytes []byte, fieldTypeBytes []byte) *Extractor {
if err != nil {
panic(fmt.Sprintf(`error parsing field type %v: %v`, fieldType, err.Error()))
}
case `Bool`, `Byte`, `Int16`, `Int32`, `Int64`, `Float`, `Double`, `Date`, `DateTime`:
case `Bool`, `Byte`, `Int16`, `Int32`, `Int64`, `Float`, `Double`, `Date`, `DateTime`, `Time`:
// do nothing
default:
panic(fmt.Sprintf(`'%v' is not a valid field type`, fieldType[0]))
Expand Down Expand Up @@ -153,6 +154,16 @@ func (e *Extractor) Extract(data []byte) FileData {
panic(fmt.Sprintf(`'%v' is not a valid date, expecting a format of 'YYYY-mm-dd HH:MM:SS'`, value))
}
dateTimeFields[field.Name] = dateValue
case `Time`:
if value == `` {
dateTimeFields[field.Name] = nil
continue
}
timeValue, err := time.Parse(timeFormat, value)
if err != nil {
panic(fmt.Sprintf(`'%v' is not a valid time, expecting a format of 'HH:MM:SS'`, value))
}
dateTimeFields[field.Name] = timeValue
case `Blob`, `SpatialObj`:
if value == `` {
blobFields[field.Name] = nil
Expand Down
13 changes: 7 additions & 6 deletions sdk/import_file/import_file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import (
"time"
)

const fieldNames string = "Field1\000Field2\000Field3\000Field4\000Field5\000Field6\000Field7\000Field8\000Field9\000Field10\000Field11\000Field12\000Field13\000Field14\000Field15\000Field16"
const fieldTypes string = "Bool\000Byte\000Int16\000Int32\000Int64\000Float\000Double\000FixedDecimal;19;2\000String;100\000WString;100\000V_String;10000\000V_WString;100000\000Date\000DateTime\000Blob;10\000SpatialObj;100"
const record1 string = "true\0002\000100\0001000\00010000\00012.34\0001.23\000234.56\000\"ABC\"\000\"Hello \"\000\" World\"\000\"abcdefg\"\0002020-01-01\0002020-01-02 03:04:05\000\000"
const record2 string = "false\0002\000-100\000-1000\000-10000\000-12.34\000-1.23\000-234.56\000\"DE|\"FG\"\000HIJK\000LMNOP\000\"QRSTU\r\nVWXYZ\"\0002020-02-03\0002020-01-02 13:14:15\000\000"
const record3 string = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
const record4 string = "true\00042\000-110\000392\0002340\00012\00041.22\00098.2\000\"\"\000\"\"\000\"\"\000\"\"\0002020-02-13\0002020-11-02 13:14:15\000\000"
const fieldNames string = "Field1\000Field2\000Field3\000Field4\000Field5\000Field6\000Field7\000Field8\000Field9\000Field10\000Field11\000Field12\000Field13\000Field14\000Field15\000Field16\000Field17"
const fieldTypes string = "Bool\000Byte\000Int16\000Int32\000Int64\000Float\000Double\000FixedDecimal;19;2\000String;100\000WString;100\000V_String;10000\000V_WString;100000\000Date\000DateTime\000Blob;10\000SpatialObj;100\000Time"
const record1 string = "true\0002\000100\0001000\00010000\00012.34\0001.23\000234.56\000\"ABC\"\000\"Hello \"\000\" World\"\000\"abcdefg\"\0002020-01-01\0002020-01-02 03:04:05\000\000\00010:01:01"
const record2 string = "false\0002\000-100\000-1000\000-10000\000-12.34\000-1.23\000-234.56\000\"DE|\"FG\"\000HIJK\000LMNOP\000\"QRSTU\r\nVWXYZ\"\0002020-02-03\0002020-01-02 13:14:15\000\000\000"
const record3 string = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\00017:02:01"
const record4 string = "true\00042\000-110\000392\0002340\00012\00041.22\00098.2\000\"\"\000\"\"\000\"\"\000\"\"\0002020-02-13\0002020-11-02 13:14:15\000\000\000"

func TestPreprocessTextFile(t *testing.T) {
file, err := os.Open(filepath.Join(`..`, `sdk_test_passthrough_simulation.txt`))
Expand Down Expand Up @@ -71,6 +71,7 @@ func TestExtractData(t *testing.T) {
{Name: `Field14`, Type: `DateTime`},
{Name: `Field15`, Type: `Blob`, Size: 10},
{Name: `Field16`, Type: `SpatialObj`, Size: 100},
{Name: `Field17`, Type: `Time`},
}
if !reflect.DeepEqual(fields, expectedFields) {
t.Fatalf("expected\n%v\nbut got\n%v", expectedFields, fields)
Expand Down
6 changes: 6 additions & 0 deletions sdk/incoming_recordinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

const dateFormat = `2006-01-02`
const dateTimeFormat = `2006-01-02 15:04:05`
const timeFormat = `15:04:05`

type xmlMetaInfo struct {
Connection string `xml:"connection,attr"`
Expand Down Expand Up @@ -110,6 +111,8 @@ func (i IncomingRecordInfo) GetTimeField(name string) (IncomingTimeField, error)
return generateTimeField(field, dateFormat, 10), nil
case `DateTime`:
return generateTimeField(field, dateTimeFormat, 19), nil
case `Time`:
return generateTimeField(field, timeFormat, 8), nil
default:
return IncomingTimeField{}, fmt.Errorf(`the '%v' field is not a time field, it is '%v'`, name, field.Type)
}
Expand Down Expand Up @@ -199,6 +202,9 @@ func incomingRecordInfoFromString(config string) (IncomingRecordInfo, error) {
case `DateTime`:
field.GetBytes = generateGetFixedBytes(startAt, 20)
startAt += 20
case `Time`:
field.GetBytes = generateGetFixedBytes(startAt, 9)
startAt += 9
default:
return IncomingRecordInfo{}, fmt.Errorf(`field '%v' has invalid field type '%v'`, field.Name, field.Type)
}
Expand Down
29 changes: 28 additions & 1 deletion sdk/outgoing_recordinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,23 @@ func NewDateTimeField(name string, source string) NewOutgoingField {
}
}

func NewTimeField(name string, source string) NewOutgoingField {
return func() *outgoingField {
return &outgoingField{
Name: name,
Type: `Time`,
Source: source,
Size: 8,
CurrentValue: make([]byte, 9),
nullSetter: setNormalFieldNull,
nullGetter: getNormalFieldNull,
dateTimeSetter: setTime,
dateTimeGetter: getTime,
isFixedLen: true,
}
}
}

func NewStringField(name string, source string, size int) NewOutgoingField {
return func() *outgoingField {
return &outgoingField{
Expand Down Expand Up @@ -494,6 +511,16 @@ func setDateTime(value time.Time, f *outgoingField) {
copy(f.CurrentValue[:19], valueStr)
}

func getTime(f *outgoingField) time.Time {
value, _ := time.Parse(timeFormat, string(f.CurrentValue[:8]))
return value
}

func setTime(value time.Time, f *outgoingField) {
valueStr := value.Format(timeFormat)
copy(f.CurrentValue[:8], valueStr)
}

func (f *outgoingField) SetDateTime(value time.Time) {
f.dateTimeSetter(value, f)
f.nullSetter(0, f)
Expand Down Expand Up @@ -679,7 +706,7 @@ func NewOutgoingRecordInfo(fields []NewOutgoingField) (*OutgoingRecordInfo, []st
info.IntFields[field.Name] = field
case `Float`, `Double`, `FixedDecimal`:
info.FloatFields[field.Name] = field
case `Date`, `DateTime`:
case `Date`, `DateTime`, `Time`:
info.DateTimeFields[field.Name] = field
case `String`, `WString`, `V_String`, `V_WString`:
info.StringFields[field.Name] = field
Expand Down
1 change: 1 addition & 0 deletions sdk/outgoing_recordinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ func TestGetNull(t *testing.T) {
sdk.NewDateTimeField(`Field14`, `source`),
sdk.NewBlobField(`Field15`, `source`, 1000000),
sdk.NewSpatialObjField(`Field16`, `source`, 1000000),
sdk.NewTimeField(`Field17`, `source`),
})

for _, field := range info.FloatFields {
Expand Down
2 changes: 2 additions & 0 deletions sdk/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,8 @@ func goOnInputConnectionOpened(handle unsafe.Pointer) {
fixedSize += 11
case `DateTime`:
fixedSize += 20
case `Time`:
fixedSize += 9
case `String`:
fixedSize += uint32(field.Size) + 1
case `WString`:
Expand Down
4 changes: 2 additions & 2 deletions sdk/sdk_nocache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ func TestNoCache(t *testing.T) {
if collector.PacketsReceived != 4 {
t.Fatalf(`expected 4 packets but got %v`, collector.PacketsReceived)
}
if fields := len(collector.Data); fields != 16 {
t.Fatalf(`expected 16 fields but got %v`, fields)
if fields := len(collector.Data); fields != 17 {
t.Fatalf(`expected 17 fields but got %v`, fields)
}
if records := len(collector.Data[`Field1`]); records != 4 {
t.Fatalf(`expected 4 records but got %v`, records)
Expand Down
20 changes: 14 additions & 6 deletions sdk/sdk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ func (i *TestInputTool) OnComplete() {
sdk.NewDateField(`Field14`, source),
sdk.NewDateTimeField(`Field15`, source),
sdk.NewSpatialObjField(`Field16`, source, 1000000),
sdk.NewTimeField(`Field17`, source),
})
i.OutputConfig = output
i.Output.Open(output)
Expand All @@ -109,6 +110,7 @@ func (i *TestInputTool) OnComplete() {
output.DateTimeFields[`Field14`].SetDateTime(time.Date(2020, 1, index, 0, 0, 0, 0, time.UTC))
output.DateTimeFields[`Field15`].SetDateTime(time.Date(2020, 1, index, 0, 0, 0, 0, time.UTC))
output.BlobFields[`Field16`].SetBlob([]byte{byte(index)})
output.DateTimeFields[`Field17`].SetDateTime(time.Date(0, 0, 0, 12, 31, index, 0, time.UTC))
i.Output.Write()
}
i.Output.UpdateProgress(1)
Expand Down Expand Up @@ -329,15 +331,15 @@ func TestOutputRecordsToTestRunner(t *testing.T) {
if collector.Name != `Output` {
t.Fatalf(`expected 'Output' but got '%v'`, collector.Name)
}
if fields := collector.Config.NumFields(); fields != 16 {
t.Fatalf("expected 16 fields but got %v", fields)
if fields := collector.Config.NumFields(); fields != 17 {
t.Fatalf("expected 17 fields but got %v", fields)
}
outputConfig := implementation.Output.Metadata()
if outputConfig != implementation.OutputConfig {
t.Fatalf(`expected same instance but got %v and %v`, outputConfig, implementation.OutputConfig)
}
if length := len(collector.Data); length != 16 {
t.Fatalf(`expected 16 fields but got %v`, length)
if length := len(collector.Data); length != 17 {
t.Fatalf(`expected 17 fields but got %v`, length)
}
if length := len(collector.Data[`Field3`]); length != 10 {
t.Fatalf(`expected [0 1 2 3 4 5 6 7 8 9] but got %v`, collector.Data[`Field3`])
Expand Down Expand Up @@ -391,6 +393,9 @@ func TestOutputRecordsToTestRunner(t *testing.T) {
if !bytes.Equal(collector.Data[`Field16`][i].([]byte), []byte{byte(i)}) {
t.Fatalf(`expected [[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]] but got %v`, collector.Data[`Field16`])
}
if collector.Data[`Field17`][i] != time.Date(0, 1, 1, 12, 31, i, 0, time.UTC) {
t.Fatalf(`expected [0000-01-01 12:31:00 +0000 UTC 0000-01-01 12:31:01 +0000 UTC 0000-01-01 12:31:02 +0000 UTC 0000-01-01 12:31:03 +0000 UTC 0000-01-01 12:31:04 +0000 UTC 0000-01-01 12:31:05 +0000 UTC 0000-01-01 12:31:06 +0000 UTC 0000-01-01 12:31:07 +0000 UTC 0000-01-01 12:31:08 +0000 UTC 0000-01-01 12:31:09 +0000 UTC] but got %v`, collector.Data[`Field17`])
}
}
if collector.Progress != 1.0 {
t.Fatalf(`expected 1.0 but got %v`, collector.Progress)
Expand Down Expand Up @@ -462,8 +467,8 @@ func TestPassthroughSimulation(t *testing.T) {
collector := runner.CaptureOutgoingAnchor(`Output`)
runner.ConnectInput(`Input`, `sdk_test_passthrough_simulation.txt`)
runner.SimulateLifecycle()
if len(collector.Data) != 16 {
t.Fatalf(`expected 16 fields but got %v`, len(collector.Data))
if len(collector.Data) != 17 {
t.Fatalf(`expected 17 fields but got %v`, len(collector.Data))
}
if recordCount := len(collector.Data[`Field1`]); recordCount != 4 {
t.Fatalf(`expected 4 records but got %v`, recordCount)
Expand Down Expand Up @@ -516,6 +521,9 @@ func TestPassthroughSimulation(t *testing.T) {
if expectedValues := []interface{}{nil, nil, nil, nil}; !reflect.DeepEqual(expectedValues, collector.Data[`Field16`]) {
t.Fatalf(`expected %v but got %v`, expectedValues, collector.Data[`Field16`])
}
if expectedValues := []interface{}{time.Date(0, 1, 1, 10, 1, 1, 0, time.UTC), nil, time.Date(0, 1, 1, 17, 2, 1, 0, time.UTC), nil}; !reflect.DeepEqual(expectedValues, collector.Data[`Field17`]) {
t.Fatalf(`expected %v but got %v`, expectedValues, collector.Data[`Field17`])
}
}

type WriteBeforeOpeningOutput struct {
Expand Down
12 changes: 6 additions & 6 deletions sdk/sdk_test_passthrough_simulation.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Field1|Field2|Field3|Field4|Field5|Field6|Field7|Field8 |Field9 |Field10 |Field11 |Field12 |Field13 |Field14 |Field15|Field16
Bool |Byte |Int16 |Int32 |Int64 |Float |Double|FixedDecimal;19;2|String;100|WString;100|V_String;10000|V_WString;100000|Date |DateTime |Blob;10|SpatialObj;100
true |2 |100 |1000 |10000 |12.34 |1.23 | 234.56 |"ABC" |"Hello " |" World" |"abcdefg" |2020-01-01|2020-01-02 03:04:05| |
false |2 |-100 |-1000 |-10000|-12.34|-1.23 | -234.56 |"DE|\"FG" |HIJK | LMNOP |"QRSTU\r\nVWXYZ"|2020-02-03|2020-01-02 13:14:15| |
| | | | | | | | | | | | | | |
true |42 |-110 |392 |2340 |12 |41.22 | 98.2 |"" |"" | "" |"" |2020-02-13|2020-11-02 13:14:15| |
Field1|Field2|Field3|Field4|Field5|Field6|Field7|Field8 |Field9 |Field10 |Field11 |Field12 |Field13 |Field14 |Field15|Field16 |Field17
Bool |Byte |Int16 |Int32 |Int64 |Float |Double|FixedDecimal;19;2|String;100|WString;100|V_String;10000|V_WString;100000|Date |DateTime |Blob;10|SpatialObj;100 |Time
true |2 |100 |1000 |10000 |12.34 |1.23 | 234.56 |"ABC" |"Hello " |" World" |"abcdefg" |2020-01-01|2020-01-02 03:04:05| | |10:01:01
false |2 |-100 |-1000 |-10000|-12.34|-1.23 | -234.56 |"DE|\"FG" |HIJK | LMNOP |"QRSTU\r\nVWXYZ"|2020-02-03|2020-01-02 13:14:15| | |
| | | | | | | | | | | | | | | |17:02:01
true |42 |-110 |392 |2340 |12 |41.22 | 98.2 |"" |"" | "" |"" |2020-02-13|2020-11-02 13:14:15| | |
4 changes: 3 additions & 1 deletion sdk/test_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ func (f *FilePusher) OnComplete() {
infoEditor.AddDateField(field.Name, source)
case `DateTime`:
infoEditor.AddDateTimeField(field.Name, source)
case `Time`:
infoEditor.AddTimeField(field.Name, source)
case `String`:
infoEditor.AddStringField(field.Name, source, field.Size)
case `WString`:
Expand Down Expand Up @@ -229,7 +231,7 @@ func (r *RecordCollector) OnInputConnectionOpened(connection InputConnection) {
case `String`, `WString`, `V_String`, `V_WString`:
stringField, _ := r.Config.GetStringField(field.Name)
r.stringFields[field.Name] = stringField.GetValue
case `Date`, `DateTime`:
case `Date`, `DateTime`, `Time`:
timeField, _ := r.Config.GetTimeField(field.Name)
r.timeFields[field.Name] = timeField.GetValue
case `Blob`, `SpatialObj`:
Expand Down

0 comments on commit 264eb53

Please sign in to comment.