New type system - Decimals
This commit is contained in:
+129
-113
@@ -8,8 +8,7 @@ uses
|
||||
System.RTTI;
|
||||
|
||||
type
|
||||
// Corrected dfVoid to dkVoid and added void type support
|
||||
TDataKind = (dkVoid, dkOrdinal, dkFloat, dkText, dkTimestamp, dkRecord, dkTuple, dkArray, dkEnum, dkMethod);
|
||||
TDataKind = (dkVoid, dkOrdinal, dkFloat, dkText, dkTimestamp, dkDecimal, dkRecord, dkTuple, dkArray, dkEnum, dkMethod);
|
||||
|
||||
IDataType = interface
|
||||
{$region 'private'}
|
||||
@@ -82,6 +81,23 @@ type
|
||||
function CreateValue(const AValue: TDateTime): IDataTimestampValue;
|
||||
end;
|
||||
|
||||
// Represents a fixed-point decimal data value.
|
||||
IDataDecimalValue = interface(IDataValue)
|
||||
{$region 'private'}
|
||||
function GetValue: Int64;
|
||||
{$endregion}
|
||||
property Value: Int64 read GetValue;
|
||||
end;
|
||||
|
||||
// Represents the type of a fixed-point decimal data value.
|
||||
IDataDecimalType = interface(IDataType)
|
||||
{$region 'private'}
|
||||
function GetScale: Integer;
|
||||
{$endregion}
|
||||
function CreateValue(const AValue: Int64): IDataDecimalValue;
|
||||
property Scale: Integer read GetScale;
|
||||
end;
|
||||
|
||||
IDataEnumValue = interface(IDataValue)
|
||||
{$region 'private'}
|
||||
function GetValue: Integer;
|
||||
@@ -190,6 +206,7 @@ type
|
||||
function AsFloat: IDataFloatValue; inline;
|
||||
function AsText: IDataTextValue; inline;
|
||||
function AsTimestamp: IDataTimestampValue; inline;
|
||||
function AsDecimal: IDataDecimalValue; inline;
|
||||
function AsRecord: IDataRecordValue; inline;
|
||||
function AsTuple: IDataTupleValue; inline;
|
||||
function AsArray: IDataArrayValue; inline;
|
||||
@@ -204,6 +221,7 @@ type
|
||||
class operator Implicit(const A: IDataFloatValue): TDataType.TValue; overload; inline;
|
||||
class operator Implicit(const A: IDataTextValue): TDataType.TValue; overload; inline;
|
||||
class operator Implicit(const A: IDataTimestampValue): TDataType.TValue; overload; inline;
|
||||
class operator Implicit(const A: IDataDecimalValue): TDataType.TValue; overload; inline;
|
||||
class operator Implicit(const A: IDataEnumValue): TDataType.TValue; overload; inline;
|
||||
class operator Implicit(const A: IDataMethodValue): TDataType.TValue; overload; inline;
|
||||
class operator Implicit(const A: IDataRecordValue): TDataType.TValue; overload; inline;
|
||||
@@ -266,6 +284,33 @@ type
|
||||
function CreateValue(const AValue: TDateTime): IDataTimestampValue; inline;
|
||||
end;
|
||||
|
||||
TDecimal = record
|
||||
type
|
||||
TValue = record
|
||||
private
|
||||
// The wrapped interface instance.
|
||||
FDecimalValue: IDataDecimalValue;
|
||||
function GetValue: Int64; inline;
|
||||
public
|
||||
constructor Create(const ADecimalValue: IDataDecimalValue);
|
||||
|
||||
class operator Implicit(const A: IDataDecimalValue): TDataType.TDecimal.TValue; overload; inline;
|
||||
class operator Implicit(const A: TDataType.TDecimal.TValue): IDataDecimalValue; overload; inline;
|
||||
|
||||
property Value: Int64 read GetValue;
|
||||
end;
|
||||
|
||||
private
|
||||
FDecimalType: IDataDecimalType;
|
||||
function GetScale: Integer; inline;
|
||||
public
|
||||
constructor Create(const ADecimalType: IDataDecimalType);
|
||||
class operator Implicit(const A: IDataDecimalType): TDataType.TDecimal; overload; inline;
|
||||
class operator Implicit(const A: TDataType.TDecimal): IDataDecimalType; overload; inline;
|
||||
function CreateValue(const AValue: Int64): TDataType.TDecimal.TValue; inline;
|
||||
property Scale: Integer read GetScale;
|
||||
end;
|
||||
|
||||
TEnum = record
|
||||
private
|
||||
FEnumType: IDataEnumType;
|
||||
@@ -343,6 +388,7 @@ type
|
||||
FArrayTypeRegistry: TDictionary<IDataType, IDataArrayType>;
|
||||
FRecordTypeRegistry: TDictionary<TArray<TRecordField>, IDataRecordType>;
|
||||
FMethodTypeRegistry: TDictionary<TPair<IDataType, IDataType>, IDataMethodType>;
|
||||
FDecimalTypes: TArray<IDataDecimalType>;
|
||||
class constructor CreateClass;
|
||||
class destructor DestroyClass;
|
||||
public
|
||||
@@ -355,6 +401,7 @@ type
|
||||
class operator Implicit(const A: TDataType.TFloat): TDataType; overload; inline;
|
||||
class operator Implicit(const A: TDataType.TText): TDataType; overload; inline;
|
||||
class operator Implicit(const A: TDataType.TTimestamp): TDataType; overload; inline;
|
||||
class operator Implicit(const A: TDataType.TDecimal): TDataType; overload; inline;
|
||||
class operator Implicit(const A: TDataType.TEnum): TDataType; overload; inline;
|
||||
class operator Implicit(const A: TDataType.TMethod): TDataType; overload; inline;
|
||||
class operator Implicit(const A: TDataType.TRecord): TDataType; overload; inline;
|
||||
@@ -367,6 +414,7 @@ type
|
||||
class function Float: TDataType.TFloat; static; inline;
|
||||
class function Text: TDataType.TText; static; inline;
|
||||
class function Timestamp: TDataType.TTimestamp; static; inline;
|
||||
class function DecimalOf(const AScale: Integer): TDataType.TDecimal; static;
|
||||
class function Tuple: TDataType.TTuple; static; inline;
|
||||
class function MethodOf(const AArgType, AResultType: IDataType): TDataType.TMethod; static;
|
||||
class function ArrayOf(const AElementType: IDataType): TDataType.TArray; static;
|
||||
@@ -374,25 +422,6 @@ type
|
||||
class function RecordOf(const Fields: array of TRecordField): TDataType.TRecord; overload; static;
|
||||
class function EnumOf(const AName: string; const AIdentifiers: array of string): TDataType.TEnum; static;
|
||||
|
||||
// Value factories
|
||||
class function FromOrdinal(const AValue: Int64): IDataOrdinalValue; static; inline;
|
||||
class function FromFloat(const AValue: Double): IDataFloatValue; static; inline;
|
||||
class function FromText(const AValue: string): IDataTextValue; static; inline;
|
||||
class function FromTimestamp(const AValue: TDateTime): IDataTimestampValue; static; inline;
|
||||
class function FromTuple(const AItems: array of IDataValue): IDataTupleValue; static;
|
||||
class function FromMethod(const AMethodType: TDataType.TMethod; const AValue: TMethod.TProc): IDataMethodValue; static; inline;
|
||||
|
||||
// Casting
|
||||
function AsOrdinal: TDataType.TOrdinal; inline;
|
||||
function AsFloat: TDataType.TFloat; inline;
|
||||
function AsText: TDataType.TText; inline;
|
||||
function AsTimestamp: TDataType.TTimestamp; inline;
|
||||
function AsRecord: TDataType.TRecord; inline;
|
||||
function AsTuple: TDataType.TTuple; inline;
|
||||
function AsArray: TDataType.TArray; inline;
|
||||
function AsEnum: TDataType.TEnum; inline;
|
||||
function AsMethod: TDataType.TMethod; inline;
|
||||
|
||||
property DataType: IDataType read FDataType;
|
||||
property Name: String read GetName;
|
||||
property Kind: TDataKind read GetKind;
|
||||
@@ -408,6 +437,7 @@ uses
|
||||
Myc.Data.Types.Float,
|
||||
Myc.Data.Types.Text,
|
||||
Myc.Data.Types.Timestamp,
|
||||
Myc.Data.Types.Decimal,
|
||||
Myc.Data.Types.Arrays,
|
||||
Myc.Data.Types.Records,
|
||||
Myc.Data.Types.Tuple,
|
||||
@@ -422,6 +452,28 @@ begin
|
||||
DataType := ADataType;
|
||||
end;
|
||||
|
||||
{ TDataType.TDecimal.TValue }
|
||||
|
||||
constructor TDataType.TDecimal.TValue.Create(const ADecimalValue: IDataDecimalValue);
|
||||
begin
|
||||
FDecimalValue := ADecimalValue;
|
||||
end;
|
||||
|
||||
function TDataType.TDecimal.TValue.GetValue: Int64;
|
||||
begin
|
||||
Result := FDecimalValue.Value;
|
||||
end;
|
||||
|
||||
class operator TDataType.TDecimal.TValue.Implicit(const A: IDataDecimalValue): TDataType.TDecimal.TValue;
|
||||
begin
|
||||
Result.FDecimalValue := A;
|
||||
end;
|
||||
|
||||
class operator TDataType.TDecimal.TValue.Implicit(const A: TDataType.TDecimal.TValue): IDataDecimalValue;
|
||||
begin
|
||||
Result := A.FDecimalValue;
|
||||
end;
|
||||
|
||||
{ TDataType.TVoid }
|
||||
|
||||
constructor TDataType.TVoid.Create(const AVoidType: IDataVoidType);
|
||||
@@ -532,6 +584,33 @@ begin
|
||||
Result := A.FTimestampType;
|
||||
end;
|
||||
|
||||
{ TDataType.TDecimal }
|
||||
|
||||
constructor TDataType.TDecimal.Create(const ADecimalType: IDataDecimalType);
|
||||
begin
|
||||
FDecimalType := ADecimalType;
|
||||
end;
|
||||
|
||||
function TDataType.TDecimal.CreateValue(const AValue: Int64): TDataType.TDecimal.TValue;
|
||||
begin
|
||||
Result.Create(FDecimalType.CreateValue(AValue));
|
||||
end;
|
||||
|
||||
function TDataType.TDecimal.GetScale: Integer;
|
||||
begin
|
||||
Result := FDecimalType.Scale;
|
||||
end;
|
||||
|
||||
class operator TDataType.TDecimal.Implicit(const A: IDataDecimalType): TDataType.TDecimal;
|
||||
begin
|
||||
Result.FDecimalType := A;
|
||||
end;
|
||||
|
||||
class operator TDataType.TDecimal.Implicit(const A: TDataType.TDecimal): IDataDecimalType;
|
||||
begin
|
||||
Result := A.FDecimalType;
|
||||
end;
|
||||
|
||||
{ TDataType.TEnum }
|
||||
|
||||
constructor TDataType.TEnum.Create(const AEnumType: IDataEnumType);
|
||||
@@ -710,9 +789,16 @@ begin
|
||||
end;
|
||||
|
||||
class constructor TDataType.CreateClass;
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
FArrayTypeRegistry := TDictionary<IDataType, IDataArrayType>.Create;
|
||||
FRecordTypeRegistry := TDictionary<TArray<TRecordField>, IDataRecordType>.Create(TRecordFieldComparer.Create);
|
||||
|
||||
SetLength(FDecimalTypes, 19);
|
||||
for i := 0 to 18 do
|
||||
FDecimalTypes[i] := TImplDataDecimalType.Create(i);
|
||||
|
||||
FMethodTypeRegistry :=
|
||||
TDictionary<TPair<IDataType, IDataType>, IDataMethodType>.Create(
|
||||
TEqualityComparer<TPair<IDataType, IDataType>>.Construct(
|
||||
@@ -737,6 +823,7 @@ class destructor TDataType.DestroyClass;
|
||||
begin
|
||||
FArrayTypeRegistry.Free;
|
||||
FRecordTypeRegistry.Free;
|
||||
FDecimalTypes := nil;
|
||||
FMethodTypeRegistry.Free;
|
||||
end;
|
||||
|
||||
@@ -760,67 +847,11 @@ begin
|
||||
Result.Create(res);
|
||||
end;
|
||||
|
||||
function TDataType.AsArray: TDataType.TArray;
|
||||
class function TDataType.DecimalOf(const AScale: Integer): TDataType.TDecimal;
|
||||
begin
|
||||
if (FDataType.Kind <> dkArray) then
|
||||
raise EInvalidCast.Create('Array expected');
|
||||
Result.Create(IDataArrayType(FDataType));
|
||||
end;
|
||||
|
||||
function TDataType.AsEnum: TDataType.TEnum;
|
||||
begin
|
||||
if (FDataType.Kind <> dkEnum) then
|
||||
raise EInvalidCast.Create('Enum expected');
|
||||
Result.Create(IDataEnumType(FDataType));
|
||||
end;
|
||||
|
||||
function TDataType.AsFloat: TDataType.TFloat;
|
||||
begin
|
||||
if (FDataType.Kind <> dkFloat) then
|
||||
raise EInvalidCast.Create('Float expected');
|
||||
Result.Create(IDataFloatType(FDataType));
|
||||
end;
|
||||
|
||||
function TDataType.AsMethod: TDataType.TMethod;
|
||||
begin
|
||||
if (FDataType.Kind <> dkMethod) then
|
||||
raise EInvalidCast.Create('Method expected');
|
||||
Result.Create(IDataMethodType(FDataType));
|
||||
end;
|
||||
|
||||
function TDataType.AsOrdinal: TDataType.TOrdinal;
|
||||
begin
|
||||
if (FDataType.Kind <> dkOrdinal) then
|
||||
raise EInvalidCast.Create('Ordinal expected');
|
||||
Result.Create(IDataOrdinalType(FDataType));
|
||||
end;
|
||||
|
||||
function TDataType.AsRecord: TDataType.TRecord;
|
||||
begin
|
||||
if (FDataType.Kind <> dkRecord) then
|
||||
raise EInvalidCast.Create('Record expected');
|
||||
Result.Create(IDataRecordType(FDataType));
|
||||
end;
|
||||
|
||||
function TDataType.AsText: TDataType.TText;
|
||||
begin
|
||||
if (FDataType.Kind <> dkText) then
|
||||
raise EInvalidCast.Create('Text expected');
|
||||
Result.Create(IDataTextType(FDataType));
|
||||
end;
|
||||
|
||||
function TDataType.AsTimestamp: TDataType.TTimestamp;
|
||||
begin
|
||||
if (FDataType.Kind <> dkTimestamp) then
|
||||
raise EInvalidCast.Create('Timestamp expected');
|
||||
Result.Create(IDataTimestampType(FDataType));
|
||||
end;
|
||||
|
||||
function TDataType.AsTuple: TDataType.TTuple;
|
||||
begin
|
||||
if (FDataType.Kind <> dkTuple) then
|
||||
raise EInvalidCast.Create('Tuple expected');
|
||||
Result.Create(IDataTupleType(FDataType));
|
||||
if (AScale < 0) or (AScale > 18) then
|
||||
raise EArgumentException.Create('Scale for decimal must be between 0 and 18.');
|
||||
Result.Create(FDecimalTypes[AScale]);
|
||||
end;
|
||||
|
||||
class function TDataType.EnumOf(const AName: string; const AIdentifiers: array of string): TDataType.TEnum;
|
||||
@@ -833,38 +864,6 @@ begin
|
||||
Result.Create(TImplDataFloatType.Singleton);
|
||||
end;
|
||||
|
||||
class function TDataType.FromFloat(const AValue: Double): IDataFloatValue;
|
||||
begin
|
||||
Result := TDataType.Float.CreateValue(AValue);
|
||||
end;
|
||||
|
||||
class function TDataType.FromMethod(const AMethodType: TDataType.TMethod; const AValue: TMethod.TProc): IDataMethodValue;
|
||||
begin
|
||||
if not Assigned(AMethodType.FMethodType) then // Check underlying interface
|
||||
raise EArgumentException.Create('AMethodType');
|
||||
Result := AMethodType.CreateValue(AValue);
|
||||
end;
|
||||
|
||||
class function TDataType.FromOrdinal(const AValue: Int64): IDataOrdinalValue;
|
||||
begin
|
||||
Result := TDataType.Ordinal.CreateValue(AValue);
|
||||
end;
|
||||
|
||||
class function TDataType.FromText(const AValue: string): IDataTextValue;
|
||||
begin
|
||||
Result := TDataType.Text.CreateValue(AValue);
|
||||
end;
|
||||
|
||||
class function TDataType.FromTimestamp(const AValue: TDateTime): IDataTimestampValue;
|
||||
begin
|
||||
Result := TDataType.Timestamp.CreateValue(AValue);
|
||||
end;
|
||||
|
||||
class function TDataType.FromTuple(const AItems: array of IDataValue): IDataTupleValue;
|
||||
begin
|
||||
Result := TDataType.Tuple.CreateValue(AItems);
|
||||
end;
|
||||
|
||||
function TDataType.GetKind: TDataKind;
|
||||
begin
|
||||
Result := FDataType.Kind;
|
||||
@@ -965,6 +964,11 @@ begin
|
||||
Result.FDataType := A.FArrayType;
|
||||
end;
|
||||
|
||||
class operator TDataType.Implicit(const A: TDataType.TDecimal): TDataType;
|
||||
begin
|
||||
Result.FDataType := A.FDecimalType;
|
||||
end;
|
||||
|
||||
class operator TDataType.Implicit(const A: TDataType.TEnum): TDataType;
|
||||
begin
|
||||
Result.FDataType := A.FEnumType;
|
||||
@@ -1025,6 +1029,13 @@ begin
|
||||
Result := IDataArrayValue(FDataValue);
|
||||
end;
|
||||
|
||||
function TDataType.TValue.AsDecimal: IDataDecimalValue;
|
||||
begin
|
||||
if (FDataValue.DataType.Kind <> dkDecimal) then
|
||||
raise EInvalidCast.Create('Decimal expected');
|
||||
Result := IDataDecimalValue(FDataValue);
|
||||
end;
|
||||
|
||||
function TDataType.TValue.AsEnum: IDataEnumValue;
|
||||
begin
|
||||
if (FDataValue.DataType.Kind <> dkEnum) then
|
||||
@@ -1106,6 +1117,11 @@ begin
|
||||
Result.FDataValue := A;
|
||||
end;
|
||||
|
||||
class operator TDataType.TValue.Implicit(const A: IDataDecimalValue): TDataType.TValue;
|
||||
begin
|
||||
Result.FDataValue := A;
|
||||
end;
|
||||
|
||||
class operator TDataType.TValue.Implicit(const A: IDataEnumValue): TDataType.TValue;
|
||||
begin
|
||||
Result.FDataValue := A;
|
||||
|
||||
Reference in New Issue
Block a user