sqldbrestcsv.pp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2019 by the Free Pascal development team
  4. SQLDB REST CSV input/output
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit sqldbrestcsv;
  12. {$mode objfpc}{$H+}
  13. interface
  14. uses
  15. Classes, SysUtils, sqldbrestio, fpjson, sqldbrestschema, csvreadwrite;
  16. Type
  17. { TCSVInputStreamer }
  18. TCSVInputStreamer = Class(TRestInputStreamer)
  19. private
  20. FCSV: TCSVParser;
  21. FValues,
  22. FFields : TStrings;
  23. Protected
  24. Property CSV : TCSVParser Read FCSV;
  25. Public
  26. Destructor Destroy; override;
  27. Function SelectObject(aIndex : Integer) : Boolean; override;
  28. function GetContentField(aName: UTF8string): TJSONData; override;
  29. procedure InitStreaming; override;
  30. end;
  31. { TCSVOutputStreamer }
  32. TCSVOutputStreamer = Class(TRestOutputStreamer)
  33. Private
  34. FCSV : TCSVBuilder;
  35. FField : integer;
  36. FRow : Integer;
  37. Public
  38. procedure EndData; override;
  39. procedure EndRow; override;
  40. procedure FinalizeOutput; override;
  41. procedure StartData; override;
  42. procedure StartRow; override;
  43. // Return Nil for null field.
  44. procedure WriteField(aPair: TRestFieldPair); override;
  45. procedure WriteMetadata(aFieldList: TRestFieldPairArray); override;
  46. Procedure CreateErrorContent(aCode : Integer; Const aMessage: String); override;
  47. Property CSV : TCSVBuilder Read FCSV;
  48. Public
  49. Destructor Destroy; override;
  50. Class Function GetContentType: String; override;
  51. procedure InitStreaming; override;
  52. end;
  53. implementation
  54. uses DateUtils;
  55. { TCSVInputStreamer }
  56. procedure TCSVInputStreamer.InitStreaming;
  57. begin
  58. FreeAndNil(FCSV);
  59. FreeAndNil(FFields);
  60. FCSV:=TCSVParser.Create;
  61. FCSV.SetSource(Stream);
  62. FCSV.QuoteChar:='"';
  63. FCSV.Delimiter:=',';
  64. FCSV.LineEnding:=LineEnding;//
  65. FFields:=TStringList.Create;
  66. FValues:=TStringList.Create;
  67. While FCSV.ParseNextCell and (FCSV.CurrentRow=0) do
  68. FFields.Add(FCSV.CurrentCellText);
  69. end;
  70. destructor TCSVInputStreamer.Destroy;
  71. begin
  72. FreeAndNil(FCSV);
  73. FreeAndNil(FValues);
  74. FreeAndNil(FFields);
  75. inherited Destroy;
  76. end;
  77. function TCSVInputStreamer.SelectObject(aIndex: Integer): Boolean;
  78. begin
  79. Result:=(aIndex=0) and (FCSV<>Nil) and (FCSV.CurrentRow=1);
  80. if Not Result then
  81. exit;
  82. Repeat
  83. // We are on the first cell
  84. FValues.Add(FCSV.CurrentCellText);
  85. until Not (FCSV.ParseNextCell) or (FCSV.CurrentRow=2);
  86. end;
  87. function TCSVInputStreamer.GetContentField(aName: UTF8string): TJSONData;
  88. Var
  89. Idx : Integer;
  90. begin
  91. Idx:=FFields.IndexOf(aName);
  92. if (Idx>=0) and (Idx<FValues.Count) then
  93. Result:=TJSONString.Create(FValues[Idx])
  94. else
  95. Result:=nil;
  96. end;
  97. { TCSVOutputStreamer }
  98. procedure TCSVOutputStreamer.EndData;
  99. begin
  100. FRow:=0;
  101. end;
  102. procedure TCSVOutputStreamer.EndRow;
  103. begin
  104. if FField=0 then exit;
  105. inc(FRow);
  106. FCSV.AppendRow;
  107. FField:=0;
  108. end;
  109. procedure TCSVOutputStreamer.FinalizeOutput;
  110. begin
  111. // Nothing needs to be done.
  112. FreeAndNil(FCSV);
  113. end;
  114. procedure TCSVOutputStreamer.StartData;
  115. begin
  116. FRow:=0;
  117. end;
  118. procedure TCSVOutputStreamer.StartRow;
  119. begin
  120. Inc(FRow);
  121. end;
  122. procedure TCSVOutputStreamer.WriteField(aPair: TRestFieldPair);
  123. Var
  124. S : UTF8String;
  125. begin
  126. S:=FieldToString(aPair.RestField.FieldType,aPair.DBField);
  127. FCSV.AppendCell(S);
  128. Inc(FField);
  129. end;
  130. procedure TCSVOutputStreamer.WriteMetadata(aFieldList: TRestFieldPairArray);
  131. Var
  132. P : TREstFieldPair;
  133. begin
  134. For P in aFieldList do
  135. FCSV.AppendCell(P.RestField.PublicName);
  136. FCSV.AppendRow;
  137. end;
  138. Class function TCSVOutputStreamer.GetContentType: String;
  139. begin
  140. Result:='text/csv';
  141. end;
  142. procedure TCSVOutputStreamer.CreateErrorContent(aCode: Integer; const aMessage: String);
  143. Var
  144. S : String;
  145. begin
  146. S:=Format('<html><title>Error %d: %s</title>',[aCode,aMessage]);
  147. S:=S+Format('<body><h1>Error %d : %s</h1></body></html>',[aCode,aMessage]);
  148. Stream.WriteBuffer(S[1],Length(S));
  149. end;
  150. destructor TCSVOutputStreamer.Destroy;
  151. begin
  152. FreeAndNil(FCSV);
  153. inherited Destroy;
  154. end;
  155. procedure TCSVOutputStreamer.InitStreaming;
  156. begin
  157. FCSV:=TCSVBuilder.Create;
  158. FCSV.SetOutput(Stream);
  159. FCSV.QuoteChar:='"';
  160. FCSV.Delimiter:=',';
  161. FCSV.QuoteOuterWhitespace:=True;
  162. end;
  163. initialization
  164. TCSVInputStreamer.RegisterStreamer('CSV');
  165. TCSVOutputStreamer.RegisterStreamer('CSV');
  166. end.