This commit is contained in:
Daniele Teti 2019-07-06 19:33:24 +02:00
commit de441f63a3
11 changed files with 198 additions and 12 deletions

View File

@ -98,6 +98,9 @@ begin
case aRQLFIlter.Token of case aRQLFIlter.Token of
tkEq: tkEq:
begin begin
if aRQLFIlter.RightValueType = vtNull then
Result := Format('(%s IS NULL)', [lDBFieldName])
else
Result := Format('(%s = %s)', [lDBFieldName, lValue]); Result := Format('(%s = %s)', [lDBFieldName, lValue]);
end; end;
tkLt: tkLt:
@ -118,6 +121,9 @@ begin
end; end;
tkNe: tkNe:
begin begin
if aRQLFIlter.RightValueType = vtNull then
Result := Format('(%s IS NOT NULL)', [lDBFieldName])
else
Result := Format('(%s != %s)', [lDBFieldName, lValue]); Result := Format('(%s != %s)', [lDBFieldName, lValue]);
end; end;
tkContains: tkContains:

View File

@ -106,6 +106,9 @@ begin
case aRQLFIlter.Token of case aRQLFIlter.Token of
tkEq: tkEq:
begin begin
if aRQLFIlter.RightValueType = vtNull then
Result := Format('(%s IS NULL)', [lDBFieldName])
else
Result := Format('(%s = %s)', [lDBFieldName, lValue]); Result := Format('(%s = %s)', [lDBFieldName, lValue]);
end; end;
tkLt: tkLt:
@ -126,6 +129,9 @@ begin
end; end;
tkNe: tkNe:
begin begin
if aRQLFIlter.RightValueType = vtNull then
Result := Format('(%s IS NOT NULL)', [lDBFieldName])
else
Result := Format('(%s != %s)', [lDBFieldName, lValue]); Result := Format('(%s != %s)', [lDBFieldName, lValue]);
end; end;
tkContains: tkContains:

View File

@ -97,6 +97,9 @@ begin
case aRQLFIlter.Token of case aRQLFIlter.Token of
tkEq: tkEq:
begin begin
if aRQLFIlter.RightValueType = vtNull then
Result := Format('(%s IS NULL)', [lDBFieldName])
else
Result := Format('(%s = %s)', [lDBFieldName, lValue]); Result := Format('(%s = %s)', [lDBFieldName, lValue]);
end; end;
tkLt: tkLt:
@ -117,6 +120,9 @@ begin
end; end;
tkNe: tkNe:
begin begin
if aRQLFIlter.RightValueType = vtNull then
Result := Format('(%s IS NOT NULL)', [lDBFieldName])
else
Result := Format('(%s != %s)', [lDBFieldName, lValue]); Result := Format('(%s != %s)', [lDBFieldName, lValue]);
end; end;
tkContains: tkContains:

View File

@ -91,6 +91,9 @@ begin
case aRQLFIlter.Token of case aRQLFIlter.Token of
tkEq: tkEq:
begin begin
if aRQLFIlter.RightValueType = vtNull then
Result := Format('(%s IS NULL)', [lDBFieldName])
else
Result := Format('(%s = %s)', [lDBFieldName, lValue]); Result := Format('(%s = %s)', [lDBFieldName, lValue]);
end; end;
tkLt: tkLt:
@ -111,6 +114,9 @@ begin
end; end;
tkNe: tkNe:
begin begin
if aRQLFIlter.RightValueType = vtNull then
Result := Format('(%s IS NOT NULL)', [lDBFieldName])
else
Result := Format('(%s != %s)', [lDBFieldName, lValue]); Result := Format('(%s != %s)', [lDBFieldName, lValue]);
end; end;
tkContains: tkContains:

View File

@ -92,6 +92,9 @@ begin
case aRQLFIlter.Token of case aRQLFIlter.Token of
tkEq: tkEq:
begin begin
if aRQLFIlter.RightValueType = vtNull then
Result := Format('(%s IS NULL)', [lDBFieldName])
else
Result := Format('(%s = %s)', [lDBFieldName, lValue]); Result := Format('(%s = %s)', [lDBFieldName, lValue]);
end; end;
tkLt: tkLt:
@ -112,6 +115,9 @@ begin
end; end;
tkNe: tkNe:
begin begin
if aRQLFIlter.RightValueType = vtNull then
Result := Format('(%s IS NOT NULL)', [lDBFieldName])
else
Result := Format('(%s != %s)', [lDBFieldName, lValue]); Result := Format('(%s != %s)', [lDBFieldName, lValue]);
end; end;
tkContains: tkContains:

View File

@ -78,7 +78,7 @@ type
tkOpenPar, tkClosedPar, tkOpenBracket, tkCloseBracket, tkComma, tkSemicolon, tkPlus, tkMinus, tkDblQuote, tkOpenPar, tkClosedPar, tkOpenBracket, tkCloseBracket, tkComma, tkSemicolon, tkPlus, tkMinus, tkDblQuote,
tkQuote, tkSpace, tkContains, tkIn, tkUnknown); tkQuote, tkSpace, tkContains, tkIn, tkUnknown);
TRQLValueType = (vtInteger, vtString, vtBoolean, vtIntegerArray, vtStringArray); TRQLValueType = (vtInteger, vtString, vtBoolean, vtNull, vtIntegerArray, vtStringArray);
TRQLCustom = class; TRQLCustom = class;
@ -188,6 +188,7 @@ type
function MatchFieldNumericValue(out lFieldValue: string): Boolean; function MatchFieldNumericValue(out lFieldValue: string): Boolean;
function MatchFieldArrayValue(out lFieldValue: string): Boolean; function MatchFieldArrayValue(out lFieldValue: string): Boolean;
function MatchFieldBooleanValue(out lFieldValue: string): Boolean; function MatchFieldBooleanValue(out lFieldValue: string): Boolean;
function MatchFieldNullValue(out lFieldValue: string): Boolean;
function MatchSymbol(const Symbol: Char): Boolean; function MatchSymbol(const Symbol: Char): Boolean;
procedure SaveCurPos; procedure SaveCurPos;
procedure BackToLastPos; procedure BackToLastPos;
@ -618,10 +619,12 @@ begin
if MatchFieldBooleanValue(lFieldValue) then if MatchFieldBooleanValue(lFieldValue) then
lValueType := vtBoolean lValueType := vtBoolean
else if MatchFieldNullValue(LFieldValue) then
lValueType := vtNull
else if MatchFieldNumericValue(lFieldValue) then else if MatchFieldNumericValue(lFieldValue) then
lValueType := vtInteger lValueType := vtInteger
else else
Error('Expected numeric or boolean value'); Error('Expected numeric, boolean or null value');
end; end;
EatWhiteSpaces; EatWhiteSpaces;
if GetToken <> tkClosedPar then if GetToken <> tkClosedPar then
@ -911,6 +914,23 @@ begin
Exit(False); Exit(False);
end; end;
function TRQL2SQL.MatchFieldNullValue(out lFieldValue: string): Boolean;
var
lChar: Char;
begin
lFieldValue := '';
lChar := C(0).ToLower;
if (lChar = 'n') and (C(1).ToLower = 'u') and (C(2).ToLower = 'l') and (C(3).ToLower = 'l') then
begin
Skip(4);
Result := True;
lFieldValue := 'NULL';
end
else
Exit(False)
end;
function TRQL2SQL.MatchFieldNumericValue(out lFieldValue: string): Boolean; function TRQL2SQL.MatchFieldNumericValue(out lFieldValue: string): Boolean;
var var
lChar: Char; lChar: Char;

View File

@ -74,6 +74,36 @@ type
class procedure Serialize(const ADict: TMVCStringDictionary; const AJSONObject: TJsonObject); inline; class procedure Serialize(const ADict: TMVCStringDictionary; const AJSONObject: TJsonObject); inline;
end; end;
TMVCGUIDSerializer = class(TInterfacedObject, IMVCTypeSerializer)
public
procedure SerializeAttribute(
const AElementValue: TValue;
const APropertyName: string;
const ASerializerObject: TObject;
const AAttributes: TArray<TCustomAttribute>
);
procedure SerializeRoot(
const AObject: TObject;
out ASerializerObject: TObject;
const AAttributes: TArray<TCustomAttribute>;
const ASerializationAction: TMVCSerializationAction = nil
);
procedure DeserializeAttribute(
var AElementValue: TValue;
const APropertyName: string;
const ASerializerObject: TObject;
const AAttributes: TArray<TCustomAttribute>
);
procedure DeserializeRoot(
const ASerializerObject: TObject;
const AObject: TObject;
const AAttributes: TArray<TCustomAttribute>
);
end;
implementation implementation
uses uses
@ -249,4 +279,59 @@ begin
ASerializerObject := lOutObject; ASerializerObject := lOutObject;
end; end;
{ TMVCGUIDSerializer }
procedure TMVCGUIDSerializer.DeserializeAttribute(var AElementValue: TValue; const APropertyName: string;
const ASerializerObject: TObject; const AAttributes: TArray<TCustomAttribute>);
function GUIDFromString(const AString: string): TGUID;
var
LGuidStr: string;
begin
// delphi uuid format: {ae502abe-430b-b23a-2878-2d18d6a6e465}
// string uuid without braces and dashes: ae502abe430bb23a28782d18d6a6e465
if AString.Length = 32 then
LGuidStr := Format('{%s-%s-%s-%s-%s}', [AString.Substring(0, 8), AString.Substring(8, 4),
AString.Substring(12, 4), AString.Substring(16, 4),AString.Substring(20, 12)])
// string uuid without braces: ae502abe-430b-b23a-2878-2d18d6a6e465
else if AString.Length = 36 then
LGuidStr := Format('{%s}', [AString])
else
LGuidStr := AString;
Result := StringToGUID(LGuidStr);
end;
var
LJson: TJDOJsonObject;
LGuid: TGUID;
begin
LJson := ASerializerObject as TJDOJsonObject;
if LJSON.Values[APropertyName].Typ in [jdtNone, jdtObject] then { json nulls are recognized as jdtObject }
LGuid := TGUID.Empty
else
LGuid := GUIDFromString(LJSON.S[APropertyName]);
AElementValue := TValue.From<TGUID>(LGuid);
end;
procedure TMVCGUIDSerializer.DeserializeRoot(const ASerializerObject, AObject: TObject;
const AAttributes: TArray<TCustomAttribute>);
begin
// not implemented
end;
procedure TMVCGUIDSerializer.SerializeAttribute(const AElementValue: TValue; const APropertyName: string;
const ASerializerObject: TObject; const AAttributes: TArray<TCustomAttribute>);
begin
(ASerializerObject as TJDOJsonObject).S[APropertyName] := AElementValue.AsType<TGUID>.ToString;
end;
procedure TMVCGUIDSerializer.SerializeRoot(const AObject: TObject; out ASerializerObject: TObject;
const AAttributes: TArray<TCustomAttribute>; const ASerializationAction: TMVCSerializationAction);
begin
// not implemented
end;
end. end.

View File

@ -176,6 +176,8 @@ begin
GetTypeSerializers.Add(TypeInfo(TMemoryStream), lStreamSerializer); GetTypeSerializers.Add(TypeInfo(TMemoryStream), lStreamSerializer);
fStringDictionarySerializer := TMVCStringDictionarySerializer.Create; fStringDictionarySerializer := TMVCStringDictionarySerializer.Create;
GetTypeSerializers.Add(TypeInfo(TMVCStringDictionary), TMVCStringDictionarySerializer.Create); GetTypeSerializers.Add(TypeInfo(TMVCStringDictionary), TMVCStringDictionarySerializer.Create);
GetTypeSerializers.Add(TypeInfo(TGUID), TMVCGUIDSerializer.Create);
end; end;
procedure TMVCJsonDataObjectsSerializer.AttributeToJsonDataValue(const AJsonObject: TJDOJsonObject; procedure TMVCJsonDataObjectsSerializer.AttributeToJsonDataValue(const AJsonObject: TJDOJsonObject;

View File

@ -1,3 +1,5 @@
ne(value,null)
eq(value,null)
eq(value,false) eq(value,false)
eq(value,true) eq(value,true)
in ( value , [ 1 , 2 , 3 ] ) in ( value , [ 1 , 2 , 3 ] )

View File

@ -216,6 +216,13 @@ type
property NullableString: TMVCNullable<string> read FNullableString write FNullableString; property NullableString: TMVCNullable<string> read FNullableString write FNullableString;
end; end;
TEntityCustomWithGuid = class(TEntityCustom)
private
FGuidValue: TGUID;
public
property GuidValue: TGUID read FGuidValue write FGuidValue;
end;
TColorEnum = (RED, GREEN, BLUE); TColorEnum = (RED, GREEN, BLUE);
TEntityWithEnums = class TEntityWithEnums = class

View File

@ -103,6 +103,8 @@ type
procedure TestSerializeDeSerializeEntityWithEnums; procedure TestSerializeDeSerializeEntityWithEnums;
[Test] [Test]
procedure TestStringDictionary; procedure TestStringDictionary;
[Test]
procedure TestSerializeDeserializeGuid;
end; end;
@ -1273,6 +1275,44 @@ begin
end; end;
end; end;
procedure TMVCTestSerializerJsonDataObjects.TestSerializeDeserializeGuid;
const
JSON =
'{' +
'"GuidValue":"{AEED1A0F-9061-40F0-9FDA-D69AE7F20222}",' +
'"Id":1,' +
'"Code":2,' +
'"Name":"João Antônio"' +
'}';
var
LEntity: TEntityCustomWithGuid;
LJson: string;
begin
LEntity := TEntityCustomWithGuid.Create;
try
LEntity.Id := 1;
LEntity.Code := 2;
LEntity.name := 'João Antônio';
LEntity.GuidValue := StringToGuid('{AEED1A0F-9061-40F0-9FDA-D69AE7F20222}');
LJson := FSerializer.SerializeObject(LEntity);
Assert.AreEqual(JSON, LJson);
finally
LEntity.Free;
end;
LEntity := TEntityCustomWithGuid.Create;
try
FSerializer.DeserializeObject(LJson, LEntity);
Assert.AreEqual(Int64(1), LEntity.Id);
Assert.AreEqual(Integer(2), LEntity.Code);
Assert.AreEqual('João Antônio', LEntity.name);
Assert.AreEqual(StringToGuid('{AEED1A0F-9061-40F0-9FDA-D69AE7F20222}'), LEntity.GuidValue);
finally
LEntity.Free;
end;
end;
procedure TMVCTestSerializerJsonDataObjects.TestSerializeNil; procedure TMVCTestSerializerJsonDataObjects.TestSerializeNil;
begin begin
Assert.areEqual('null', FSerializer.SerializeObject(nil)); Assert.areEqual('null', FSerializer.SerializeObject(nil));