Repository URL to install this package:
|
Version:
3.2.0 ▾
|
{
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 ((FRow is TJSONArray) or not HasOption(ooSparse)) 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.