-
-
Notifications
You must be signed in to change notification settings - Fork 37
Expand file tree
/
Copy pathCloudAPI.RequestArgument.pas
More file actions
279 lines (254 loc) · 8.33 KB
/
CloudAPI.RequestArgument.pas
File metadata and controls
279 lines (254 loc) · 8.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
unit CloudAPI.RequestArgument;
interface
uses
CloudAPI.Request,
CloudAPI.Parameter,
CloudAPI.Types,
System.Rtti,
System.SysUtils,
System.TypInfo,
System.Generics.Collections;
type
TcaTypeConverter = class(TDictionary < string, TFunc < TValue, string >> )
end;
TcaRequestArgument = class
private
class var fCurrent: TcaRequestArgument;
private
fConverter: TcaTypeConverter;
fRtti: TRttiContext;
public
constructor Create;
destructor Destroy; override;
procedure RegisterConverter<T>(AConverter: TFunc<TValue, string>);
procedure RegisterToJson<T>;
function ObjToParams(AArguments: Pointer; AType: TRttiType; ADefaultParam: TcaParameter)
: TArray<TcaParameter>; overload;
function ObjToParams<T>(AArguments: T): TArray<TcaParameter>; overload;
function ObjToRequest<T>(AArguments: T): IcaRequest; overload;
function ConvertToString(AValue: TValue): string;
function TryConvertToString(AValue: TValue; var AStringValue: string): Boolean;
function TryGetConverterName(AValue: TValue; var AConverterName: string): Boolean;
function ParsePrototype(AType: Pointer; var ARttiType: TRttiType; var ADefaltParam: TcaParameter;
var Resourse: string; var AMethod: TcaMethod): Boolean;
function ParseLimitInfo(ARttiType: TRttiType; AResourse: string; ALimitInfo: TcaRequestLimit): Boolean;
class function Current: TcaRequestArgument;
class constructor Create;
class destructor Destroy;
end;
implementation
uses
CloudAPI.Attributes,
CloudAPI.Converter.BasicTypes, CloudAPI.Client.Base;
function GetShortStringString(const ShortStringPointer: PByte): string;
var
ShortStringLength: Byte;
FirstShortStringCharacter: MarshaledAString;
ConvertedLength: Cardinal;
UnicodeCharacters: array [Byte] of Char;
// cannot be more than 255 characters, reserve 1 character for terminating null
begin
if not Assigned(ShortStringPointer) then
Result := ''
else
begin
ShortStringLength := ShortStringPointer^;
if ShortStringLength = 0 then
Result := ''
else
begin
FirstShortStringCharacter := MarshaledAString(ShortStringPointer + 1);
ConvertedLength := UTF8ToUnicode(UnicodeCharacters, Length(UnicodeCharacters), FirstShortStringCharacter,
ShortStringLength);
// UTF8ToUnicode will always include the null terminator character in the Result:
ConvertedLength := ConvertedLength - 1;
SetString(Result, UnicodeCharacters, ConvertedLength);
end;
end;
end;
{ TcaRequestArgument }
function TcaRequestArgument.TryConvertToString(AValue: TValue; var AStringValue: string): Boolean;
var
LName: string;
begin
Result := TryGetConverterName(AValue, LName);
if Result then
AStringValue := fConverter[LName](AValue)
end;
function TcaRequestArgument.TryGetConverterName(AValue: TValue; var AConverterName: string): Boolean;
begin
if AValue.IsEmpty then
begin
AConverterName := 'AValue.IsEmpty';
Exit(False);
end;
AConverterName := GetShortStringString(@AValue.TypeInfo.Name);
Result := fConverter.ContainsKey(AConverterName);
end;
function TcaRequestArgument.ConvertToString(AValue: TValue): string;
begin
if not TryConvertToString(AValue, Result) then
raise ENotSupportedException.CreateFmt('Converter for "%S" not supported', [AValue.ToString]);
end;
class constructor TcaRequestArgument.Create;
begin
fCurrent := TcaRequestArgument.Create;
end;
class destructor TcaRequestArgument.Destroy;
begin
fCurrent.Free;
end;
function TcaRequestArgument.ObjToParams(AArguments: Pointer; AType: TRttiType; ADefaultParam: TcaParameter)
: TArray<TcaParameter>;
var
LRttiField: TRttiField;
LRttiAttr: TCustomAttribute;
LParam: TcaParameter;
lParamList: TList<TcaParameter>;
LArguments: Pointer;
lIsCaParameter: Boolean;
begin
if AType.TypeKind = TTypeKind.tkClass then // <------Viktor Akselrod
LArguments := PPointer(AArguments)^
else
LArguments := AArguments;
if not Assigned(LArguments) then
Exit;
lParamList := TList<TcaParameter>.Create;
try
for LRttiField in AType.GetFields do
begin
lIsCaParameter := False;
LParam := ADefaultParam;
LParam.IsRequired := False;
LParam.Name := LRttiField.Name;
LParam.Value := LRttiField.GetValue(LArguments);
for LRttiAttr in LRttiField.GetAttributes do
begin
if LRttiAttr is TcaCustomAttribute then
lIsCaParameter := True; // Поле является параметром для CloudAPI
if LRttiAttr is caIsRequairedAttribute then
LParam.IsRequired := (LRttiAttr as caIsRequairedAttribute).IsRequired
else if LRttiAttr is caNameAttribute then
LParam.Name := (LRttiAttr as caNameAttribute).Name
else if LRttiAttr is caDefaultValueAttribute then
LParam.DefaultValue := (LRttiAttr as caDefaultValueAttribute).ToString
else if LRttiAttr is caParameterTypeAttribute then
LParam.ParameterType := (LRttiAttr as caParameterTypeAttribute).ParameterType;
end;
if lIsCaParameter then
lParamList.Add(LParam);
end;
Result := lParamList.ToArray;
finally
lParamList.Free;
end;
end;
function TcaRequestArgument.ObjToRequest<T>(AArguments: T): IcaRequest;
var
LRttiType: TRttiType;
LParam: TcaParameter;
lParams: TArray<TcaParameter>;
lRes: string;
lMethod: TcaMethod;
begin
// Result := ObjToRequest(@AArguments, TypeInfo(T));
Result := TcaRequest.Create;
// ParsePrototype(AType, LRttiType, LParam, lRes, lMethod);
ParsePrototype(TypeInfo(T), LRttiType, LParam, lRes, lMethod);
Result.Resource := lRes;
Result.Method := lMethod;
ParseLimitInfo(LRttiType, Result.Resource, Result.LimitInfo);
// lParams := ObjToParams(AArguments, LRttiType, LParam);
lParams := ObjToParams(@AArguments, LRttiType, LParam);
for LParam in lParams do
Result.AddParam(LParam);
end;
function TcaRequestArgument.ParseLimitInfo(ARttiType: TRttiType; AResourse: string;
ALimitInfo: TcaRequestLimit): Boolean;
var
LRttiAttr: TCustomAttribute;
begin
Result := True;
for LRttiAttr in ARttiType.GetAttributes do
begin
if LRttiAttr is caLimitedMethodAttribute then
begin
ALimitInfo := TcaRequestLimit.Create( //
(LRttiAttr as caLimitedMethodAttribute).Limit, //
AResourse, //
(LRttiAttr as caLimitedMethodAttribute).IsGlobal)
end;
end;
end;
function TcaRequestArgument.ParsePrototype(AType: Pointer; var ARttiType: TRttiType; var ADefaltParam: TcaParameter;
var Resourse: string; var AMethod: TcaMethod): Boolean;
var
LRttiAttr: TCustomAttribute;
begin
Result := True;
ADefaltParam.ParameterType := TcaParameterType.QueryString;
AMethod := TcaMethod.GET;
ARttiType := fRtti.GetType(AType);
for LRttiAttr in ARttiType.GetAttributes do
begin
if LRttiAttr is caNameAttribute then
Resourse := (LRttiAttr as caNameAttribute).Name;
if LRttiAttr is caMethodAttribute then
AMethod := (LRttiAttr as caMethodAttribute).Method;
if LRttiAttr is caParameterTypeAttribute then
ADefaltParam.ParameterType := (LRttiAttr as caParameterTypeAttribute).ParameterType;
end;
end;
procedure TcaRequestArgument.RegisterConverter<T>(AConverter: TFunc<TValue, string>);
var
LTypeInfo: PTypeInfo;
LName: string;
begin
LTypeInfo := TypeInfo(T);
LName := string(LTypeInfo.Name);
fConverter.AddOrSetValue(LName, AConverter);
end;
procedure TcaRequestArgument.RegisterToJson<T>;
begin
RegisterConverter<T>(
function(AValue: TValue): string
var
lData: T;
lCA: TCloudApiClientBase;
begin
lData := AValue.AsType<T>;
lCA := TCloudApiClientBase.Create;
try
Result := lCA.Serializer.Serialize<T>(lData);
finally
lCA.Free;
end;
end);
end;
constructor TcaRequestArgument.Create;
begin
fConverter := TcaTypeConverter.Create();
fRtti := TRttiContext.Create();
TcaBasicConverters.BasicConverter(Self);
end;
class function TcaRequestArgument.Current: TcaRequestArgument;
begin
Result := fCurrent;
end;
destructor TcaRequestArgument.Destroy;
begin
fConverter.Free;
fRtti.Free;
end;
function TcaRequestArgument.ObjToParams<T>(AArguments: T): TArray<TcaParameter>;
var
LRttiType: TRttiType;
lDefaultParameter: TcaParameter;
lRes: string;
lMethod: TcaMethod;
begin
ParsePrototype(TypeInfo(T), LRttiType, lDefaultParameter, lRes, lMethod);
Result := ObjToParams(@AArguments, LRttiType, lDefaultParameter);
end;
end.