feat(go): reuse parsed fields across projections
This commit is contained in:
@@ -26,33 +26,27 @@ func BuildFieldsEnvelope(env envelope.FrameEnvelope) (envelope.FrameEnvelope, bo
|
||||
if !envelope.IsRealtimeTelemetryFrame(env) {
|
||||
return envelope.FrameEnvelope{}, false
|
||||
}
|
||||
rows := realtimeKVFields(env, env.Parsed)
|
||||
fields := make(map[string]any, len(rows))
|
||||
for _, row := range rows {
|
||||
key := row.Domain
|
||||
if strings.TrimSpace(row.Field) != "" {
|
||||
key += "." + row.Field
|
||||
}
|
||||
fields[key] = row.Value
|
||||
}
|
||||
if len(fields) == 0 {
|
||||
fields, fieldTypes, ok := ParsedFieldsForEnvelope(env)
|
||||
if !ok {
|
||||
return envelope.FrameEnvelope{}, false
|
||||
}
|
||||
out := envelope.FrameEnvelope{
|
||||
EventID: env.StableEventID() + ":fields",
|
||||
TraceID: env.TraceID,
|
||||
Protocol: env.Protocol,
|
||||
MessageID: env.MessageID,
|
||||
Sequence: env.Sequence,
|
||||
VIN: env.VIN,
|
||||
VehicleKeyHint: env.VehicleKeyHint,
|
||||
Phone: env.Phone,
|
||||
DeviceID: env.DeviceID,
|
||||
Plate: env.Plate,
|
||||
SourceEndpoint: env.SourceEndpoint,
|
||||
EventTimeMS: env.EventTimeMS,
|
||||
ReceivedAtMS: env.ReceivedAtMS,
|
||||
Fields: fields,
|
||||
EventID: env.StableEventID() + ":fields",
|
||||
TraceID: env.TraceID,
|
||||
Protocol: env.Protocol,
|
||||
MessageID: env.MessageID,
|
||||
Sequence: env.Sequence,
|
||||
VIN: env.VIN,
|
||||
VehicleKeyHint: env.VehicleKeyHint,
|
||||
Phone: env.Phone,
|
||||
DeviceID: env.DeviceID,
|
||||
Plate: env.Plate,
|
||||
SourceEndpoint: env.SourceEndpoint,
|
||||
EventTimeMS: env.EventTimeMS,
|
||||
ReceivedAtMS: env.ReceivedAtMS,
|
||||
Fields: fields,
|
||||
ParsedFields: fields,
|
||||
ParsedFieldTypes: fieldTypes,
|
||||
Parsed: map[string]any{
|
||||
"source_event_id": env.StableEventID(),
|
||||
"field_mapping": realtimeFieldMappingVersion,
|
||||
@@ -62,6 +56,91 @@ func BuildFieldsEnvelope(env envelope.FrameEnvelope) (envelope.FrameEnvelope, bo
|
||||
return out, true
|
||||
}
|
||||
|
||||
func EnsureParsedFields(env *envelope.FrameEnvelope) bool {
|
||||
if env == nil {
|
||||
return false
|
||||
}
|
||||
if len(env.ParsedFields) > 0 {
|
||||
if env.ParsedFieldTypes == nil {
|
||||
env.ParsedFieldTypes = inferParsedFieldTypes(env.ParsedFields)
|
||||
}
|
||||
return true
|
||||
}
|
||||
fields, fieldTypes, ok := ParsedFieldsForEnvelope(*env)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
env.ParsedFields = fields
|
||||
env.ParsedFieldTypes = fieldTypes
|
||||
return true
|
||||
}
|
||||
|
||||
func ParsedFieldsForEnvelope(env envelope.FrameEnvelope) (map[string]any, map[string]string, bool) {
|
||||
if len(env.ParsedFields) > 0 {
|
||||
fields := cloneAnyMap(env.ParsedFields)
|
||||
fieldTypes := cloneStringMap(env.ParsedFieldTypes)
|
||||
if len(fieldTypes) == 0 {
|
||||
fieldTypes = inferParsedFieldTypes(fields)
|
||||
}
|
||||
return fields, fieldTypes, true
|
||||
}
|
||||
rows := realtimeKVFields(env, env.Parsed)
|
||||
if len(rows) == 0 {
|
||||
return nil, nil, false
|
||||
}
|
||||
fields := make(map[string]any, len(rows))
|
||||
fieldTypes := make(map[string]string, len(rows))
|
||||
for _, row := range rows {
|
||||
key := realtimeKVFieldPath(row.Domain, row.Field)
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
fields[key] = row.Value
|
||||
fieldTypes[key] = row.ValueType
|
||||
}
|
||||
if len(fields) == 0 {
|
||||
return nil, nil, false
|
||||
}
|
||||
return fields, fieldTypes, true
|
||||
}
|
||||
|
||||
func inferParsedFieldTypes(fields map[string]any) map[string]string {
|
||||
if len(fields) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make(map[string]string, len(fields))
|
||||
for key, value := range fields {
|
||||
_, valueType, ok := stringifyKVValue(value)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
out[key] = valueType
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func cloneAnyMap(in map[string]any) map[string]any {
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make(map[string]any, len(in))
|
||||
for key, value := range in {
|
||||
out[key] = value
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func cloneStringMap(in map[string]string) map[string]string {
|
||||
if len(in) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make(map[string]string, len(in))
|
||||
for key, value := range in {
|
||||
out[key] = value
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
type protocolFieldMapping struct {
|
||||
Prefix string
|
||||
GBDataUnits bool
|
||||
|
||||
Reference in New Issue
Block a user