123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2019 by the Free Pascal development team
- SQLDB REST bridge JSON input/output.
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit sqldbrestjson;
- {$mode objfpc}{$H+}
- interface
- uses
- Classes, SysUtils, fpjson, db, sqldbrestio, sqldbrestschema;
- Type
- { TJSONInputStreamer }
- TJSONInputStreamer = Class(TRestInputStreamer)
- private
- FJSON: TJSONData;
- Protected
- Property JSON : TJSONData Read FJSON;
- Public
- Destructor Destroy; override;
- Function SelectObject(aIndex : Integer) : Boolean; override;
- function GetContentField(aName: UTF8string): TJSONData; override;
- procedure InitStreaming; override;
- end;
- { TJSONOutputStreamer }
- TJSONOutputStreamer = Class(TRestOutputStreamer)
- Private
- FJSON : TJSONObject;
- FData : TJSONArray;
- FRow: TJSONData;
- Public
- procedure EndData; override;
- procedure EndRow; override;
- procedure FinalizeOutput; override;
- procedure StartData; override;
- procedure StartRow; override;
- // Return Nil for null field.
- function FieldToJSON(aPair: TRestFieldPair): TJSONData; virtual;
- procedure WriteField(aPair: TRestFieldPair); override;
- procedure WriteMetadata(aFieldList: TRestFieldPairArray); override;
- Procedure CreateErrorContent(aCode : Integer; Const aMessage: String); override;
- Property JSON : TJSONObject Read FJSON;
- Property Data : TJSONArray Read FData;
- Property Row : TJSONData Read FRow;
- Public
- Destructor Destroy; override;
- Class Function GetContentType: String; override;
- procedure InitStreaming; override;
- end;
- implementation
- uses DateUtils, sqldbrestconst;
- { TJSONInputStreamer }
- procedure TJSONInputStreamer.InitStreaming;
- Var
- Msg : String;
- begin
- FreeAndNil(FJSON);
- if (Stream.Size>0) then
- begin
- try
- FJSON:=GetJSON(Stream);
- except
- On E : Exception do
- begin
- Msg:=E.Message;
- FJSON:=Nil;
- end;
- end;
- if (FJSON=Nil) then
- Raise ESQLDBRest.CreateFmt(Statuses.GetStatusCode(rsInvalidContent),'Invalid JSON input: %s',[Msg]);
- end;
- end;
- destructor TJSONInputStreamer.Destroy;
- begin
- FreeAndNil(FJSON);
- inherited Destroy;
- end;
- function TJSONInputStreamer.SelectObject(aIndex: Integer): Boolean;
- begin
- Result:=(aIndex=0) and (FJSON<>Nil) and (FJSON is TJSONObject)
- end;
- function TJSONInputStreamer.GetContentField(aName: UTF8string): TJSONData;
- Var
- D : TJSONData;
- begin
- D:=(FJSON as TJSONObject).Find(aName);
- if D<>nil then
- Result:=D.Clone
- else
- Result:=nil;
- end;
- { TJSONOutputStreamer }
- procedure TJSONOutputStreamer.EndData;
- begin
- FData:=Nil;
- end;
- procedure TJSONOutputStreamer.EndRow;
- begin
- FRow:=Nil;
- end;
- procedure TJSONOutputStreamer.FinalizeOutput;
- Var
- S : TJSONStringType;
- begin
- if ooHumanReadable in OutputOptions then
- S:=FJSON.FormatJSON()
- else
- S:=FJSON.AsJSON;
- Stream.WriteBuffer(S[1],Length(S)*SizeOf(TJSONCharType));
- FreeAndNil(FJSON);
- end;
- procedure TJSONOutputStreamer.StartData;
- begin
- FData:=TJSONArray.Create;
- FJSON.Add(GetString(rpDataRoot),FData);
- end;
- procedure TJSONOutputStreamer.StartRow;
- begin
- if (FRow<>Nil) then
- Raise ESQLDBRest.Create(Statuses.GetStatusCode(rsError),SErrDoubleRowStart);
- FRow:=TJSONObject.Create;
- FData.Add(FRow);
- end;
- Function TJSONOutputStreamer.FieldToJSON(aPair: TRestFieldPair) : TJSONData;
- Var
- F : TField;
- begin
- Result:=Nil;
- F:=aPair.DBField;;
- If (aPair.RestField.FieldType=rftUnknown) then
- raise ESQLDBRest.CreateFmt(Statuses.GetStatusCode(rsError),SErrUnsupportedRestFieldType, [aPair.RestField.PublicName]);
- If (F.IsNull) then
- Exit;
- Case aPair.RestField.FieldType of
- rftInteger : Result:=TJSONIntegerNumber.Create(F.AsInteger);
- rftLargeInt : Result:=TJSONInt64Number.Create(F.AsLargeInt);
- rftFloat : Result:=TJSONFloatNumber.Create(F.AsFloat);
- rftDate : Result:=TJSONString.Create(FormatDateTime(GetString(rpDateFormat),DateOf(F.AsDateTime)));
- rftTime : Result:=TJSONString.Create(FormatDateTime(GetString(rpTimeFormat),TimeOf(F.AsDateTime)));
- rftDateTime : Result:=TJSONString.Create(FormatDateTime(GetString(rpDateTimeFormat),F.AsDateTime));
- rftString : Result:=TJSONString.Create(F.AsString);
- rftBoolean : Result:=TJSONBoolean.Create(F.AsBoolean);
- rftBlob : Result:=TJSONString.Create(FieldToBase64(F));
- end;
- end;
- procedure TJSONOutputStreamer.WriteField(aPair: TRestFieldPair);
- Var
- D : TJSONData;
- N : UTF8String;
- begin
- N:=aPair.RestField.PublicName;
- if FRow=Nil then
- Raise ESQLDBRest.CreateFmt(Statuses.GetStatusCode(rsError),SErrFieldWithoutRow,[N]);
- D:=FieldToJSON(aPair);
- if (D=Nil) and ((not HasOption(ooSparse)) or (FRow is TJSONArray)) then
- D:=TJSONNull.Create;
- if D<>Nil then
- If FRow is TJSONArray then
- TJSONArray(FRow).Add(D)
- else if FRow is TJSONObject then
- TJSONObject(FRow).Add(N,D);
- end;
- procedure TJSONOutputStreamer.WriteMetadata(aFieldList: TRestFieldPairArray);
- Var
- A : TJSONArray;
- F : TJSONObject;
- P : TREstFieldPair;
- begin
- A:=TJSONArray.Create;
- FJSON.Add(GetString(rpMetaDataRoot),TJSOnObject.Create([GetString(rpMetaDataFields),A]));
- For P in aFieldList do
- begin
- F:=TJSONObject.Create([GetString(rpFieldNameProp),P.RestField.PublicName,GetString(rpFieldTypeProp),typenames[P.RestField.FieldType]]);
- A.Add(F);
- Case P.RestField.FieldType of
- rftDate : F.Add(GetString(rpFieldDateFormatProp),GetString(rpDateFormat));
- rftTime : F.Add(GetString(rpFieldDateFormatProp),GetString(rpTimeFormat));
- rftDateTime : F.Add(GetString(rpFieldDateFormatProp),GetString(rpDateTimeFormat));
- rftString : F.Add(GetString(rpFieldMaxLenProp),P.DBField.Size);
- end;
- end;
- end;
- Class function TJSONOutputStreamer.GetContentType: String;
- begin
- Result:='application/json';
- end;
- procedure TJSONOutputStreamer.CreateErrorContent(aCode: Integer; const aMessage: String);
- Var
- ErrorObj : TJSONObject;
- begin
- ErrorObj:=TJSONObject.Create([GetString(rpErrorCode),aCode,GetString(rpErrorMessage),aMessage]);
- FJSON.Add(GetString(rpErrorRoot),ErrorObj);
- end;
- destructor TJSONOutputStreamer.Destroy;
- begin
- FreeAndNil(FJSON);
- inherited Destroy;
- end;
- procedure TJSONOutputStreamer.InitStreaming;
- begin
- FJSON:=TJSONObject.Create;
- end;
- initialization
- TJSONInputStreamer.RegisterStreamer('json');
- TJSONOutputStreamer.RegisterStreamer('json');
- end.
|