diff --git a/pkg/schema/signal.go b/pkg/schema/signal.go index a359713..d0dfdaf 100644 --- a/pkg/schema/signal.go +++ b/pkg/schema/signal.go @@ -4,6 +4,7 @@ package schema import ( "regexp" "strings" + "unicode" ) const ( @@ -109,7 +110,7 @@ func NewSignalInfo(record []string) *SignalInfo { sig.BaseGQLType = gqlTypeFromVSPEC(baseType) } sig.GOName = goName(sig.Name) - sig.JSONName = JSONName(sig.Name) + sig.JSONName = jsonName(sig.Name) return sig } @@ -146,23 +147,51 @@ func (s *SignalInfo) GQLType() string { return s.BaseGQLType } +// goName returns the golang formated name of the signal. +// Removes the root Prefix and nonAlphaNumeric characters from the name and capitalizes the first letter. func goName(name string) string { - return nonAlphaNum.ReplaceAllString(removePrefix(name), "") + firstComponent, rest := splitAndSantizeName(name) + var nameBuilder strings.Builder + _, _ = nameBuilder.WriteRune(unicode.ToUpper(rune(firstComponent[0]))) + _, _ = nameBuilder.WriteString(firstComponent[1:]) + _, _ = nameBuilder.WriteString(rest) + return nameBuilder.String() } -// JSONName returns the json name of the signal. -func JSONName(name string) string { - n := goName(name) - // lowercase the first letter - return strings.ToLower(n[:1]) + n[1:] +// jsonName returns the JSON formated name of the signal. +// Removes the root Prefix and nonAlphaNumeric characters from the name and lowercases the first word. +func jsonName(name string) string { + firstComponent, rest := splitAndSantizeName(name) + if firstComponent == "" { + return "" + } + + var nameBuilder strings.Builder + for i, r := range firstComponent { + if i == 0 || unicode.IsUpper(r) { + // Lowercase first and any initial consecutive uppercase letters + _, _ = nameBuilder.WriteRune(unicode.ToLower(r)) + continue + } + // write the remainging characters of the first component + _, _ = nameBuilder.WriteString(firstComponent[i:]) + break + } + _, _ = nameBuilder.WriteString(rest) + return nameBuilder.String() } -func removePrefix(name string) string { - idx := strings.IndexByte(name, '.') - if idx != -1 { - return name[idx+1:] +// splitAndSantizeName removes the root branch prefix from the name and returns the first component separate from rest of the name with nonAlphaNumeric characters removed. +func splitAndSantizeName(name string) (string, string) { + splitName := strings.Split(name, ".") + + if len(splitName) == 1 { + return nonAlphaNum.ReplaceAllString(splitName[0], ""), "" } - return name + // remove branch prefix if it exists i.e. Vehcile.Speed -> Speed + splitName = splitName[1:] + + return nonAlphaNum.ReplaceAllString(splitName[0], ""), nonAlphaNum.ReplaceAllString(strings.Join(splitName[1:], ""), "") } // goTypeFromVSPEC converts vspec type to golang types. diff --git a/pkg/schema/signal_test.go b/pkg/schema/signal_test.go new file mode 100644 index 0000000..6242e21 --- /dev/null +++ b/pkg/schema/signal_test.go @@ -0,0 +1,48 @@ +package schema + +import "testing" + +func TestJSONName(t *testing.T) { + tests := []struct { + input string + expected string + }{ + { + input: "Vehicle.CurrentLocation.Altitude", + expected: "currentLocationAltitude", + }, + { + input: "Vechicle.DIMO.Source", + expected: "dimoSource", + }, + { + input: "Vehicle.DIMO.WPAState", + expected: "dimoWPAState", + }, + { + input: "Vehicle.DIMO.Aftemarket.HDOP", + expected: "dimoAftemarketHDOP", + }, + { + input: "Vehicle.DIMO.Aftemarket.WPAState", + expected: "dimoAftemarketWPAState", + }, + { + input: "Vehicle.Powertrain.CombustionEngine.ECT", + expected: "powertrainCombustionEngineECT", + }, + { + input: "Vehicle.Powertrain.CombustionEngine.Tps", + expected: "powertrainCombustionEngineTps", + }, + } + + for _, test := range tests { + t.Run(test.input, func(t *testing.T) { + result := jsonName(test.input) + if result != test.expected { + t.Errorf("Unexpected result. Expected: %s, Got: %s", test.expected, result) + } + }) + } +} diff --git a/pkg/vss/convert/payloadv1_test.go b/pkg/vss/convert/payloadv1_test.go index 64cec8a..9e0df7d 100644 --- a/pkg/vss/convert/payloadv1_test.go +++ b/pkg/vss/convert/payloadv1_test.go @@ -105,9 +105,9 @@ var ( {TokenID: 123, Timestamp: ts, Name: "vehicleIdentificationYear", ValueNumber: 2020, Source: "dimo/integration/123"}, {TokenID: 123, Timestamp: ts, Name: "exteriorAirTemperature", ValueNumber: 25, Source: "dimo/integration/123"}, {TokenID: 123, Timestamp: ts, Name: "lowVoltageBatteryCurrentVoltage", ValueNumber: 12.5, Source: "dimo/integration/123"}, - {TokenID: 123, Timestamp: ts, Name: "oBDBarometricPressure", ValueNumber: 1013.25, Source: "dimo/integration/123"}, - {TokenID: 123, Timestamp: ts, Name: "oBDEngineLoad", ValueNumber: 75, Source: "dimo/integration/123"}, - {TokenID: 123, Timestamp: ts, Name: "oBDIntakeTemp", ValueNumber: 30, Source: "dimo/integration/123"}, - {TokenID: 123, Timestamp: ts, Name: "oBDRunTime", ValueNumber: 1200, Source: "dimo/integration/123"}, + {TokenID: 123, Timestamp: ts, Name: "obdBarometricPressure", ValueNumber: 1013.25, Source: "dimo/integration/123"}, + {TokenID: 123, Timestamp: ts, Name: "obdEngineLoad", ValueNumber: 75, Source: "dimo/integration/123"}, + {TokenID: 123, Timestamp: ts, Name: "obdIntakeTemp", ValueNumber: 30, Source: "dimo/integration/123"}, + {TokenID: 123, Timestamp: ts, Name: "obdRunTime", ValueNumber: 1200, Source: "dimo/integration/123"}, } ) diff --git a/pkg/vss/convert/payloadv2_test.go b/pkg/vss/convert/payloadv2_test.go index bd92b44..b735246 100644 --- a/pkg/vss/convert/payloadv2_test.go +++ b/pkg/vss/convert/payloadv2_test.go @@ -131,16 +131,16 @@ var fullV2InputJSON = `{ var expectedV2Signals = []vss.Signal{ {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 26, 633000000, time.UTC), Name: "powertrainCombustionEngineECT", ValueNumber: 107, ValueString: "", Source: "dimo/integration/123"}, {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 27, 173000000, time.UTC), Name: "powertrainCombustionEngineMAF", ValueNumber: 475.79, ValueString: "", Source: "dimo/integration/123"}, - {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 29, 314000000, time.UTC), Name: "oBDEngineLoad", ValueNumber: 12.54912, ValueString: "", Source: "dimo/integration/123"}, + {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 29, 314000000, time.UTC), Name: "obdEngineLoad", ValueNumber: 12.54912, ValueString: "", Source: "dimo/integration/123"}, {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 29, 844000000, time.UTC), Name: "powertrainCombustionEngineTPS", ValueNumber: 23.529600000000002, ValueString: "", Source: "dimo/integration/123"}, {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 37, 235000000, time.UTC), Name: "powertrainCombustionEngineTPS", ValueNumber: 23.529600000000002, ValueString: "", Source: "dimo/integration/123"}, {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 42, 256000000, time.UTC), Name: "powertrainCombustionEngineMAF", ValueNumber: 475.79, ValueString: "", Source: "dimo/integration/123"}, - {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 44, 422000000, time.UTC), Name: "oBDEngineLoad", ValueNumber: 12.54912, ValueString: "", Source: "dimo/integration/123"}, + {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 44, 422000000, time.UTC), Name: "obdEngineLoad", ValueNumber: 12.54912, ValueString: "", Source: "dimo/integration/123"}, {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 44, 962000000, time.UTC), Name: "powertrainCombustionEngineTPS", ValueNumber: 23.529600000000002, ValueString: "", Source: "dimo/integration/123"}, {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 46, 435000000, time.UTC), Name: "currentLocationLongitude", ValueNumber: -56.50151833333334, ValueString: "", Source: "dimo/integration/123"}, {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 46, 435000000, time.UTC), Name: "currentLocationLatitude", ValueNumber: 56.27014, ValueString: "", Source: "dimo/integration/123"}, - {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 46, 435000000, time.UTC), Name: "dIMOAftermarketHDOP", ValueNumber: 1.4, ValueString: "", Source: "dimo/integration/123"}, - {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 46, 435000000, time.UTC), Name: "dIMOAftermarketNSAT", ValueNumber: 6, ValueString: "", Source: "dimo/integration/123"}, - {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 46, 435000000, time.UTC), Name: "dIMOAftermarketWPAState", ValueNumber: 0, ValueString: "COMPLETED", Source: "dimo/integration/123"}, - {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 46, 435000000, time.UTC), Name: "dIMOAftermarketSSID", ValueNumber: 0, ValueString: "foo", Source: "dimo/integration/123"}, + {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 46, 435000000, time.UTC), Name: "dimoAftermarketHDOP", ValueNumber: 1.4, ValueString: "", Source: "dimo/integration/123"}, + {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 46, 435000000, time.UTC), Name: "dimoAftermarketNSAT", ValueNumber: 6, ValueString: "", Source: "dimo/integration/123"}, + {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 46, 435000000, time.UTC), Name: "dimoAftermarketWPAState", ValueNumber: 0, ValueString: "COMPLETED", Source: "dimo/integration/123"}, + {TokenID: tokenID, Timestamp: time.Date(2024, time.April, 18, 17, 20, 46, 435000000, time.UTC), Name: "dimoAftermarketSSID", ValueNumber: 0, ValueString: "foo", Source: "dimo/integration/123"}, } diff --git a/pkg/vss/vehicle-structs.go b/pkg/vss/vehicle-structs.go index a420b8c..80eb55e 100644 --- a/pkg/vss/vehicle-structs.go +++ b/pkg/vss/vehicle-structs.go @@ -19,25 +19,25 @@ const ( // FieldCurrentLocationTimestamp Timestamp from GNSS system for current location, formatted according to ISO 8601 with UTC time zone. FieldCurrentLocationTimestamp = "currentLocationTimestamp" // FieldDIMOAftermarketHDOP Horizontal dilution of precision of GPS - FieldDIMOAftermarketHDOP = "dIMOAftermarketHDOP" + FieldDIMOAftermarketHDOP = "dimoAftermarketHDOP" // FieldDIMOAftermarketNSAT Number of sync satellites for GPS - FieldDIMOAftermarketNSAT = "dIMOAftermarketNSAT" + FieldDIMOAftermarketNSAT = "dimoAftermarketNSAT" // FieldDIMOAftermarketSSID Service Set Ientifier for the wifi. - FieldDIMOAftermarketSSID = "dIMOAftermarketSSID" + FieldDIMOAftermarketSSID = "dimoAftermarketSSID" // FieldDIMOAftermarketWPAState Indicate the current wpa state for the devices wifi - FieldDIMOAftermarketWPAState = "dIMOAftermarketWPAState" + FieldDIMOAftermarketWPAState = "dimoAftermarketWPAState" // FieldExteriorAirTemperature Air temperature outside the vehicle. FieldExteriorAirTemperature = "exteriorAirTemperature" // FieldLowVoltageBatteryCurrentVoltage Current Voltage of the low voltage battery. FieldLowVoltageBatteryCurrentVoltage = "lowVoltageBatteryCurrentVoltage" // FieldOBDBarometricPressure PID 33 - Barometric pressure - FieldOBDBarometricPressure = "oBDBarometricPressure" + FieldOBDBarometricPressure = "obdBarometricPressure" // FieldOBDEngineLoad PID 04 - Engine load in percent - 0 = no load, 100 = full load - FieldOBDEngineLoad = "oBDEngineLoad" + FieldOBDEngineLoad = "obdEngineLoad" // FieldOBDIntakeTemp PID 0F - Intake temperature - FieldOBDIntakeTemp = "oBDIntakeTemp" + FieldOBDIntakeTemp = "obdIntakeTemp" // FieldOBDRunTime PID 1F - Engine run time - FieldOBDRunTime = "oBDRunTime" + FieldOBDRunTime = "obdRunTime" // FieldPowertrainCombustionEngineECT Engine coolant temperature. FieldPowertrainCombustionEngineECT = "powertrainCombustionEngineECT" // FieldPowertrainCombustionEngineEngineOilLevel Engine oil level. diff --git a/pkg/vss/vehicle-v1-convert.go b/pkg/vss/vehicle-v1-convert.go index 9d4c727..220622a 100644 --- a/pkg/vss/vehicle-v1-convert.go +++ b/pkg/vss/vehicle-v1-convert.go @@ -154,7 +154,7 @@ func SignalsFromV1Data(baseSignal Signal, jsonData []byte) ([]Signal, error) { } } else { sig := Signal{ - Name: "dIMOAftermarketHDOP", + Name: "dimoAftermarketHDOP", TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, @@ -170,7 +170,7 @@ func SignalsFromV1Data(baseSignal Signal, jsonData []byte) ([]Signal, error) { } } else { sig := Signal{ - Name: "dIMOAftermarketNSAT", + Name: "dimoAftermarketNSAT", TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, @@ -186,7 +186,7 @@ func SignalsFromV1Data(baseSignal Signal, jsonData []byte) ([]Signal, error) { } } else { sig := Signal{ - Name: "dIMOAftermarketSSID", + Name: "dimoAftermarketSSID", TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, @@ -202,7 +202,7 @@ func SignalsFromV1Data(baseSignal Signal, jsonData []byte) ([]Signal, error) { } } else { sig := Signal{ - Name: "dIMOAftermarketWPAState", + Name: "dimoAftermarketWPAState", TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, @@ -250,7 +250,7 @@ func SignalsFromV1Data(baseSignal Signal, jsonData []byte) ([]Signal, error) { } } else { sig := Signal{ - Name: "oBDBarometricPressure", + Name: "obdBarometricPressure", TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, @@ -266,7 +266,7 @@ func SignalsFromV1Data(baseSignal Signal, jsonData []byte) ([]Signal, error) { } } else { sig := Signal{ - Name: "oBDEngineLoad", + Name: "obdEngineLoad", TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, @@ -282,7 +282,7 @@ func SignalsFromV1Data(baseSignal Signal, jsonData []byte) ([]Signal, error) { } } else { sig := Signal{ - Name: "oBDIntakeTemp", + Name: "obdIntakeTemp", TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, @@ -298,7 +298,7 @@ func SignalsFromV1Data(baseSignal Signal, jsonData []byte) ([]Signal, error) { } } else { sig := Signal{ - Name: "oBDRunTime", + Name: "obdRunTime", TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, diff --git a/pkg/vss/vehicle-v2-convert.go b/pkg/vss/vehicle-v2-convert.go index ad21df2..381380c 100644 --- a/pkg/vss/vehicle-v2-convert.go +++ b/pkg/vss/vehicle-v2-convert.go @@ -62,7 +62,7 @@ func SignalsFromV2Data(baseSignal Signal, signalName string, sigResult gjson.Res TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, - Name: "oBDBarometricPressure", + Name: "obdBarometricPressure", } sig.SetValue(val0) ret = append(ret, sig) @@ -146,7 +146,7 @@ func SignalsFromV2Data(baseSignal Signal, signalName string, sigResult gjson.Res TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, - Name: "oBDEngineLoad", + Name: "obdEngineLoad", } sig.SetValue(val0) ret = append(ret, sig) @@ -215,7 +215,7 @@ func SignalsFromV2Data(baseSignal Signal, signalName string, sigResult gjson.Res TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, - Name: "dIMOAftermarketHDOP", + Name: "dimoAftermarketHDOP", } sig.SetValue(val0) ret = append(ret, sig) @@ -229,7 +229,7 @@ func SignalsFromV2Data(baseSignal Signal, signalName string, sigResult gjson.Res TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, - Name: "oBDIntakeTemp", + Name: "obdIntakeTemp", } sig.SetValue(val0) ret = append(ret, sig) @@ -313,7 +313,7 @@ func SignalsFromV2Data(baseSignal Signal, signalName string, sigResult gjson.Res TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, - Name: "dIMOAftermarketNSAT", + Name: "dimoAftermarketNSAT", } sig.SetValue(val0) ret = append(ret, sig) @@ -369,7 +369,7 @@ func SignalsFromV2Data(baseSignal Signal, signalName string, sigResult gjson.Res TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, - Name: "oBDRunTime", + Name: "obdRunTime", } sig.SetValue(val0) ret = append(ret, sig) @@ -411,7 +411,7 @@ func SignalsFromV2Data(baseSignal Signal, signalName string, sigResult gjson.Res TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, - Name: "dIMOAftermarketSSID", + Name: "dimoAftermarketSSID", } sig.SetValue(val0) ret = append(ret, sig) @@ -522,7 +522,7 @@ func SignalsFromV2Data(baseSignal Signal, signalName string, sigResult gjson.Res TokenID: baseSignal.TokenID, Timestamp: baseSignal.Timestamp, Source: baseSignal.Source, - Name: "dIMOAftermarketWPAState", + Name: "dimoAftermarketWPAState", } sig.SetValue(val0) ret = append(ret, sig)