Refacoring data pipeline

This commit is contained in:
Michael Schimmel
2025-12-14 12:03:16 +01:00
parent 8beb5d95b2
commit f88fe9f5ef
5 changed files with 119 additions and 116 deletions
+113 -1
View File
@@ -4,7 +4,8 @@ interface
uses
System.SysUtils,
System.TypInfo;
System.TypInfo,
Myc.Data.Pipeline;
type
TDataRecord = record
@@ -110,6 +111,40 @@ type
property Layout: TLayout read FLayout;
end;
TDataRecordLayoutHelper = record helper for TDataRecord.TLayout
function FieldAsRecord<T>(const Name: String): TConverter<T, TDataRecord>;
function FieldOfRecord<T>(const Name: String): TConverter<TDataRecord, T>;
end;
type
TRecordMapping = record
Layout: TDataRecord.TLayout;
Fields: array of record
FromField, ToField: String
end;
end;
// Factory for creating specific converter instances.
TRecordConverter = record
class function DataMapping(
const Inputs: TArray<TRecordMapping>;
const Output: TDataRecord.TLayout
): TConverter<TArray<TDataRecord>, TDataRecord>; static;
class function JoinRecords(
const TargetLayout: TDataRecord.TLayout;
const Mapping: TArray<TRecordMapping>;
const Producers: TArray<TProducer<TDataRecord>>
): TConverter<TArray<TDataRecord>, TDataRecord>; static;
end;
TDataRecordHelper = record helper for TArray<TProducer<TDataRecord>>
function JoinRecords(
const TargetLayout: TDataRecord.TLayout;
const Mapping: TArray<TRecordMapping>
): TProducer<TDataRecord>; experimental;
end;
implementation
uses
@@ -569,4 +604,81 @@ begin
Result := not (A = B);
end;
function TDataRecordLayoutHelper.FieldAsRecord<T>(const Name: String): TConverter<T, TDataRecord>;
begin
var layout := Self;
var idx := IndexOf(Name);
Result :=
TConverter<T, TDataRecord>.CreateConverter(
function(const Value: T): TDataRecord
begin
Result := TDataRecord.Create(layout);
Result.SetValue(idx, Value);
end
);
end;
function TDataRecordLayoutHelper.FieldOfRecord<T>(const Name: String): TConverter<TDataRecord, T>;
begin
var idx := IndexOf(Name);
Result := TConverter<TDataRecord, T>.CreateConverter(function(const Value: TDataRecord): T begin Value.GetValue(idx, Result); end);
end;
class function TRecordConverter.DataMapping(
const Inputs: TArray<TRecordMapping>;
const Output: TDataRecord.TLayout
): TConverter<TArray<TDataRecord>, TDataRecord>;
var
Idxs: array of array of record
FromIdx, ToIdx: Integer
end;
begin
SetLength(Idxs, Length(Inputs));
for var i := 0 to High(Idxs) do
begin
SetLength(Idxs[i], Length(Inputs[i].Fields));
for var j := 0 to High(Idxs[i]) do
begin
Idxs[i][j].FromIdx := Inputs[i].Layout.IndexOf(Inputs[i].Fields[j].FromField);
Idxs[i][j].ToIdx := Output.IndexOf(Inputs[i].Fields[j].ToField);
end;
end;
Result :=
TConverter<TArray<TDataRecord>, TDataRecord>.CreateConverter(
function(const Inputs: TArray<TDataRecord>): TDataRecord
begin
Result := TDataRecord.Create(Output);
for var i := 0 to High(Idxs) do
for var j := 0 to High(Idxs[i]) do
Result.CopyValue(Inputs[i], Idxs[i][j].FromIdx, Idxs[i][j].ToIdx);
end
);
end;
class function TRecordConverter.JoinRecords(
const TargetLayout: TDataRecord.TLayout;
const Mapping: TArray<TRecordMapping>;
const Producers: TArray<TProducer<TDataRecord>>
): TConverter<TArray<TDataRecord>, TDataRecord>;
begin
var RecProvider := TConverter.Join<TDataRecord>(jmAll, Producers);
Result := TRecordConverter.DataMapping(Mapping, TargetLayout);
RecProvider.Chain(Result.Consumer);
end;
function TDataRecordHelper.JoinRecords(
const TargetLayout: TDataRecord.TLayout;
const Mapping: TArray<TRecordMapping>
): TProducer<TDataRecord>;
begin
var map := TRecordConverter.DataMapping(Mapping, TargetLayout);
TConverter.Join<TDataRecord>(jmAll, Self).Chain(map.Consumer);
Result := map.Producer;
end;
end.