mORMot and Open Source friends
Check-in [befb577145]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:{1844} fixed JSON serialization of some enumerated types, e.g. for WordBool
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: befb577145a7d879cd5ade46fddab70e9da7fb61
User & Date: ab 2015-09-01 12:33:49
Context
2015-09-02
15:03
{1845} added new TSQLRestStorageExternal.OnEngineAddComputeID and EngineAddIgnoreID properties for [201348a0af6] check-in: 334a9933e8 user: ab tags: trunk
2015-09-01
12:33
{1844} fixed JSON serialization of some enumerated types, e.g. for WordBool check-in: befb577145 user: ab tags: trunk
2015-08-31
15:41
{1843} Delphi 10 (DX Seattle) support - it was not named Delphi XE9 ;) check-in: bccfcbb7fb user: ab tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to SQLite3/mORMot.pas.

2489
2490
2491
2492
2493
2494
2495

2496
2497
2498
2499
2500
2501
2502
.....
18832
18833
18834
18835
18836
18837
18838
18839
18840
18841
18842
18843
18844
18845
18846
.....
18853
18854
18855
18856
18857
18858
18859
18860
18861
18862
18863
18864
18865
18866
18867
18868
18869
18870
18871
18872
18873
18874
18875
18876
18877
18878
18879
18880
18881
18882
.....
18889
18890
18891
18892
18893
18894
18895
18896
18897
18898
18899
18900
18901
18902
18903
18904
18905
.....
26418
26419
26420
26421
26422
26423
26424




26425
26426
26427
26428
26429
26430
26431
.....
26695
26696
26697
26698
26699
26700
26701
26702
26703
26704


26705
26706
26707
26708
26709
26710
26711
.....
26955
26956
26957
26958
26959
26960
26961
26962
26963
26964
26965
26966
26967
26968
26969
26970
26971
26972
26973
26974
26975
26976
26977
26978
26979
26980
26981
  // definition itself
  {$ifndef ISDELPHI2010}
  TEnumType = object
  {$else}
  TEnumType = record
  {$endif}
    /// specify ordinal storage size and sign

    OrdType: TOrdType;
    /// first value of enumeration type, typicaly 0
    MinValue: Longint;
    /// same as ord(high(type)): not the enumeration count, but the highest index
    MaxValue: Longint;
    /// the base type of this enumeration
    /// - always use PEnumType(typeinfo(TEnumType))^.BaseType or more useful
................................................................................
end;

procedure TSQLPropInfoRTTIEnum.GetJSONValues(Instance: TObject; W: TJSONSerializer);
var i: integer;
begin
  i := fPropInfo.GetOrdProp(Instance);
  if fSQLFieldType=sftBoolean then
    W.AddString(JSON_BOOLEAN[boolean(i)]) else
    W.Add(i);
end;

function TSQLPropInfoRTTIEnum.GetCaption(Value: RawUTF8; out IntValue: integer): string;
begin
  NormalizeValue(Value);
  IntValue := GetInteger(pointer(Value));
................................................................................
  ToSQL: boolean; var result: RawUTF8; wasSQLString: PBoolean);
var i: integer;
begin
  if wasSQLString<>nil then
    wasSQLString^ := false;
  i := fPropInfo.GetOrdProp(Instance);
  if (fSQLFieldType=sftBoolean) and not ToSQL then
    result := JSON_BOOLEAN[boolean(i)] else
    Int32ToUtf8(i,result);
end;

procedure TSQLPropInfoRTTIEnum.NormalizeValue(var Value: RawUTF8);
var i,err: integer;
begin
  i := GetInteger(pointer(Value),err);
  if err<>0 then  // we allow a value stated as text
    if fSQLFieldType=sftBoolean then
      i := Ord(IdemPropNameU(Value,'TRUE') or IdemPropNameU(Value,'YES')) else
      i := fEnumType^.GetEnumNameValue(pointer(Value),length(Value)) else
    if fSQLFieldType=sftBoolean then // normalize boolean values range to 0,1
      if Boolean(i) then
        i := 1 else
        i := 0;
  if cardinal(i)>cardinal(fEnumType^.MaxValue) then
    Value := '' else // only set a valid value
    Int32ToUtf8(i,Value);
end;

procedure TSQLPropInfoRTTIEnum.SetValue(Instance: TObject; Value: PUTF8Char;
  wasString: boolean);
................................................................................
      if fSQLFieldType=sftBoolean then
        i := Ord(IdemPropNameU(Value,'TRUE') or IdemPropNameU(Value,'YES')) else
        i := fEnumType^.GetEnumNameValue(Value); // -> convert into integer
      if cardinal(i)>cardinal(fEnumType^.MaxValue) then
        i := 0;  // only set a valid text value
    end else
    if fSQLFieldType=sftBoolean then // normalize boolean values range to 0,1
      if Boolean(i) then
        i := 1 else
        i := 0;
  end;
  fPropInfo.SetOrdProp(Instance,i);
end;


{ TSQLPropInfoRTTIChar }

................................................................................
    tkEnumeration:
      {$ifndef FPC}
      if @self=TypeInfo(Boolean) then begin
        result := sftBoolean;
        exit;
      end else
      {$endif}




      begin
        result := sftEnumerate;
        exit;
      end;
    tkFloat:
      if @self=TypeInfo(Currency) then begin
        result := sftCurrency;
................................................................................


{ TEnumType }

function TEnumType.GetEnumName(const Value): PShortString;
var Ordinal: integer;
begin
  if MaxValue<=255 then
    Ordinal := byte(Value) else
    Ordinal := word(Value);


  result := GetEnumNameOrd(Ordinal);
end;

function TEnumType.GetEnumNameOrd(Value: Integer): PShortString;
// note: FPC doesn't align NameList (cf. GetEnumName() function in typinfo.pp)
{$ifdef PUREPASCAL}
begin
................................................................................
    EnumName := Value;
    result := GetEnumNameTrimedValue(EnumName);
  end;
end;

function TEnumType.SizeInStorageAsEnum: Integer;
begin
  case MaxValue of
  0..255:     result := 1;
  256..65535: result := 2;
  else        result := 4;
  end;
end;

procedure TEnumType.SetEnumFromOrdinal(out Value; Ordinal: Integer);
begin
  case MaxValue of
  0..255:     byte(Value) := Ordinal;
  256..65535: word(Value) := Ordinal;
  else        integer(Value) := Ordinal;
  end;
end;

function TEnumType.SizeInStorageAsSet: Integer;
begin
  case MaxValue of
  0..7:   result := 1;






>







 







|







 







|












|
<
|







 







|
<
|







 







>
>
>
>







 







|
|
|
>
>







 







|
|
|
|





|
|
|
|







2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
.....
18833
18834
18835
18836
18837
18838
18839
18840
18841
18842
18843
18844
18845
18846
18847
.....
18854
18855
18856
18857
18858
18859
18860
18861
18862
18863
18864
18865
18866
18867
18868
18869
18870
18871
18872
18873
18874

18875
18876
18877
18878
18879
18880
18881
18882
.....
18889
18890
18891
18892
18893
18894
18895
18896

18897
18898
18899
18900
18901
18902
18903
18904
.....
26417
26418
26419
26420
26421
26422
26423
26424
26425
26426
26427
26428
26429
26430
26431
26432
26433
26434
.....
26698
26699
26700
26701
26702
26703
26704
26705
26706
26707
26708
26709
26710
26711
26712
26713
26714
26715
26716
.....
26960
26961
26962
26963
26964
26965
26966
26967
26968
26969
26970
26971
26972
26973
26974
26975
26976
26977
26978
26979
26980
26981
26982
26983
26984
26985
26986
  // definition itself
  {$ifndef ISDELPHI2010}
  TEnumType = object
  {$else}
  TEnumType = record
  {$endif}
    /// specify ordinal storage size and sign
    // - is prefered to MaxValue to identify the number of stored bytes
    OrdType: TOrdType;
    /// first value of enumeration type, typicaly 0
    MinValue: Longint;
    /// same as ord(high(type)): not the enumeration count, but the highest index
    MaxValue: Longint;
    /// the base type of this enumeration
    /// - always use PEnumType(typeinfo(TEnumType))^.BaseType or more useful
................................................................................
end;

procedure TSQLPropInfoRTTIEnum.GetJSONValues(Instance: TObject; W: TJSONSerializer);
var i: integer;
begin
  i := fPropInfo.GetOrdProp(Instance);
  if fSQLFieldType=sftBoolean then
    W.AddString(JSON_BOOLEAN[i<>0]) else
    W.Add(i);
end;

function TSQLPropInfoRTTIEnum.GetCaption(Value: RawUTF8; out IntValue: integer): string;
begin
  NormalizeValue(Value);
  IntValue := GetInteger(pointer(Value));
................................................................................
  ToSQL: boolean; var result: RawUTF8; wasSQLString: PBoolean);
var i: integer;
begin
  if wasSQLString<>nil then
    wasSQLString^ := false;
  i := fPropInfo.GetOrdProp(Instance);
  if (fSQLFieldType=sftBoolean) and not ToSQL then
    result := JSON_BOOLEAN[i<>0] else
    Int32ToUtf8(i,result);
end;

procedure TSQLPropInfoRTTIEnum.NormalizeValue(var Value: RawUTF8);
var i,err: integer;
begin
  i := GetInteger(pointer(Value),err);
  if err<>0 then  // we allow a value stated as text
    if fSQLFieldType=sftBoolean then
      i := Ord(IdemPropNameU(Value,'TRUE') or IdemPropNameU(Value,'YES')) else
      i := fEnumType^.GetEnumNameValue(pointer(Value),length(Value)) else
    if fSQLFieldType=sftBoolean then // normalize boolean values range to 0,1
      if i<>0 then

        i := 1;
  if cardinal(i)>cardinal(fEnumType^.MaxValue) then
    Value := '' else // only set a valid value
    Int32ToUtf8(i,Value);
end;

procedure TSQLPropInfoRTTIEnum.SetValue(Instance: TObject; Value: PUTF8Char;
  wasString: boolean);
................................................................................
      if fSQLFieldType=sftBoolean then
        i := Ord(IdemPropNameU(Value,'TRUE') or IdemPropNameU(Value,'YES')) else
        i := fEnumType^.GetEnumNameValue(Value); // -> convert into integer
      if cardinal(i)>cardinal(fEnumType^.MaxValue) then
        i := 0;  // only set a valid text value
    end else
    if fSQLFieldType=sftBoolean then // normalize boolean values range to 0,1
      if i<>0 then

        i := 1;
  end;
  fPropInfo.SetOrdProp(Instance,i);
end;


{ TSQLPropInfoRTTIChar }

................................................................................
    tkEnumeration:
      {$ifndef FPC}
      if @self=TypeInfo(Boolean) then begin
        result := sftBoolean;
        exit;
      end else
      {$endif}
      if @self=TypeInfo(WordBool) then begin // circumvent a Delphi RTTI bug
        result := sftBoolean;
        exit;
      end else
      begin
        result := sftEnumerate;
        exit;
      end;
    tkFloat:
      if @self=TypeInfo(Currency) then begin
        result := sftCurrency;
................................................................................


{ TEnumType }

function TEnumType.GetEnumName(const Value): PShortString;
var Ordinal: integer;
begin
  case OrdType of // MaxValue does not work e.g. with WordBool
  otSByte, otUByte: Ordinal := byte(Value);
  otSWord, otUWord: Ordinal := word(Value);
  else              Ordinal := integer(Value);
  end;
  result := GetEnumNameOrd(Ordinal);
end;

function TEnumType.GetEnumNameOrd(Value: Integer): PShortString;
// note: FPC doesn't align NameList (cf. GetEnumName() function in typinfo.pp)
{$ifdef PUREPASCAL}
begin
................................................................................
    EnumName := Value;
    result := GetEnumNameTrimedValue(EnumName);
  end;
end;

function TEnumType.SizeInStorageAsEnum: Integer;
begin
  case OrdType of // MaxValue does not work e.g. with WordBool
  otSByte, otUByte: result := 1;
  otSWord, otUWord: result := 2;
  else              result := 4;
  end;
end;

procedure TEnumType.SetEnumFromOrdinal(out Value; Ordinal: Integer);
begin
  case OrdType of // MaxValue does not work e.g. with WordBool
  otSByte, otUByte: byte(Value) := Ordinal;
  otSWord, otUWord: word(Value) := Ordinal;
  else              integer(Value) := Ordinal;
  end;
end;

function TEnumType.SizeInStorageAsSet: Integer;
begin
  case MaxValue of
  0..7:   result := 1;

Changes to SynSelfTests.pas.

5460
5461
5462
5463
5464
5465
5466


5467
5468
5469
5470
5471
5472
5473
      JSONToObject(O2,pointer(J),valid);
      Check(Valid);
      Check(O.Name=O2.Name);
      Check(O.Enum=O2.Enum);
      Check(O.Sets=O2.Sets);
      Check(ObjectEquals(O,O2));
    end;


    J := ObjectToJSON(O,[woHumanReadable,woHumanReadableFullSetsAsStar]);
    Check(J='{'#$D#$A#9'"Name": "3",'#$D#$A#9'"Enum": "Destroying",'#$D#$A#9'"Sets": ["*"]'#$D#$A'}');
    J := ObjectToJSON(O,[woHumanReadable,woHumanReadableFullSetsAsStar,woHumanReadableEnumSetAsComment]);
    Check(J='{'#$D#$A#9'"Name": "3",'#$D#$A#9'"Enum": "Destroying", // Idle,Started,Finished,Destroying'+
      #$D#$A#9'"Sets": ["*"] // "*" or a set of Idle,Started,Finished,Destroying'#$D#$A'}');
    O2.fName := '';
    O2.fEnum := low(E);






>
>







5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
      JSONToObject(O2,pointer(J),valid);
      Check(Valid);
      Check(O.Name=O2.Name);
      Check(O.Enum=O2.Enum);
      Check(O.Sets=O2.Sets);
      Check(ObjectEquals(O,O2));
    end;
    with PTypeInfo(TypeInfo(WordBool))^.EnumBaseType^ do
      Check(SizeInStorageAsEnum=2);
    J := ObjectToJSON(O,[woHumanReadable,woHumanReadableFullSetsAsStar]);
    Check(J='{'#$D#$A#9'"Name": "3",'#$D#$A#9'"Enum": "Destroying",'#$D#$A#9'"Sets": ["*"]'#$D#$A'}');
    J := ObjectToJSON(O,[woHumanReadable,woHumanReadableFullSetsAsStar,woHumanReadableEnumSetAsComment]);
    Check(J='{'#$D#$A#9'"Name": "3",'#$D#$A#9'"Enum": "Destroying", // Idle,Started,Finished,Destroying'+
      #$D#$A#9'"Sets": ["*"] // "*" or a set of Idle,Started,Finished,Destroying'#$D#$A'}');
    O2.fName := '';
    O2.fEnum := low(E);

Changes to SynopseCommit.inc.

1
'1.18.1843'
|
1
'1.18.1844'