Files
MycLib/Src/Data/Myc.Data.Types.Decimal.pas
T
Michael Schimmel 54d470b2f8 New type system
2025-08-26 15:49:28 +02:00

153 lines
3.6 KiB
ObjectPascal

unit Myc.Data.Types.Decimal;
interface
uses
Myc.Data.Types;
type
// Concrete implementation of the IDataDecimalType interface.
TImplDataDecimalType = class(TInterfacedObject, IDataDecimalType)
private
FScale: Integer;
strict private
class var
// Pre-cached instances for scales 0-18.
FDecimalTypes: TArray<IDataDecimalType>;
public
constructor Create(const AScale: Integer);
class constructor CreateClass;
class destructor DestroyClass;
// Returns a cached instance for the specified scale.
class function GetInstance(const AScale: Integer): IDataDecimalType; static;
// IDataType
function GetName: String;
function GetKind: TDataKind;
// IDataDecimalType
function GetScale: Integer;
function CreateValue(const AValue: Int64): IDataDecimalValue;
end;
implementation
uses
System.SysUtils,
System.Math;
type
TDataDecimalValue = class(TInterfacedObject, IDataDecimalValue)
private
FDataType: IDataDecimalType;
FValue: Int64;
public
constructor Create(const AValue: Int64; const ADataType: IDataDecimalType);
// IDataValue
function GetDataType: IDataType;
function GetAsString: string;
// IDataDecimalValue
function GetValue: Int64;
end;
{ TImplDataDecimalType }
constructor TImplDataDecimalType.Create(const AScale: Integer);
begin
inherited Create;
FScale := AScale;
end;
class constructor TImplDataDecimalType.CreateClass;
var
i: Integer;
begin
// Create and cache singleton instances for each supported scale.
SetLength(FDecimalTypes, 19);
for i := 0 to High(FDecimalTypes) do
FDecimalTypes[i] := TImplDataDecimalType.Create(i);
end;
class destructor TImplDataDecimalType.DestroyClass;
begin
FDecimalTypes := nil;
end;
class function TImplDataDecimalType.GetInstance(const AScale: Integer): IDataDecimalType;
begin
if (AScale < 0) or (AScale > High(FDecimalTypes)) then
raise EArgumentException.CreateFmt('Scale for decimal must be between 0 and %d.', [High(FDecimalTypes)]);
Result := FDecimalTypes[AScale];
end;
function TImplDataDecimalType.CreateValue(const AValue: Int64): IDataDecimalValue;
begin
Result := TDataDecimalValue.Create(AValue, Self);
end;
function TImplDataDecimalType.GetKind: TDataKind;
begin
Result := dkDecimal;
end;
function TImplDataDecimalType.GetName: String;
begin
Result := Format('Decimal(18, %d)', [FScale]);
end;
function TImplDataDecimalType.GetScale: Integer;
begin
Result := FScale;
end;
{ TDataDecimalValue }
constructor TDataDecimalValue.Create(const AValue: Int64; const ADataType: IDataDecimalType);
begin
inherited Create;
FValue := AValue;
FDataType := ADataType;
end;
function TDataDecimalValue.GetAsString: string;
var
s: string;
scale: Integer;
insertPos: Integer;
begin
s := IntToStr(abs(FValue));
scale := FDataType.Scale;
if scale > 0 then
begin
if Length(s) <= scale then
s := StringOfChar('0', scale - Length(s) + 1) + s;
insertPos := Length(s) - scale;
Result := Copy(s, 1, insertPos) + '.' + Copy(s, insertPos + 1, MaxInt);
end
else
begin
Result := s;
end;
if FValue < 0 then
Result := '-' + Result;
end;
function TDataDecimalValue.GetDataType: IDataType;
begin
Result := FDataType;
end;
function TDataDecimalValue.GetValue: Int64;
begin
Result := FValue;
end;
end.