jsondataset.pas 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766
  1. {$mode objfpc}
  2. unit JSONDataset;
  3. interface
  4. uses
  5. Types, JS, DB, Classes, SysUtils, typinfo, fpexprpars;
  6. type
  7. TBaseJSONDataset = Class;
  8. TJSONIndexDef = class;
  9. // How are rows encoded in the JSON ?
  10. TJSONRowType = (rtJSONObject, // Each row is an object.
  11. rtJSONArray // Each row is an array.
  12. );
  13. { TJSONFieldMapper }
  14. // This class is responsible for mapping the field objects of the records.
  15. TJSONFieldMapper = Class(TObject)
  16. Public
  17. // Return row TJSONData instance with data for field 'FieldName' or 'FieldIndex'.
  18. Function GetJSONDataForField(Const FieldName : String; FieldIndex : Integer; Row : JSValue) : JSValue; virtual; abstract;
  19. // Same, but now based on TField.
  20. Function GetJSONDataForField(F : TField; Row : JSValue) : JSValue; virtual;
  21. // Set data for field 'FieldName' or 'FieldIndex' to supplied TJSONData instance in row
  22. procedure SetJSONDataForField(Const FieldName : String; FieldIndex : Integer; Row,Data : JSValue); virtual; abstract;
  23. // Set data for field TField to supplied TJSONData instance
  24. procedure SetJSONDataForField(F : TField; Row,Data : JSValue); virtual;
  25. // Create a new row.
  26. Function CreateRow : JSValue; virtual; abstract;
  27. end;
  28. // JSON has no date/time type, so we use a string field.
  29. // ExtJS provides the date/time format in it's field config: 'dateFormat'
  30. // The below field classes store this in the NNNFormat field.
  31. { TJSONDateField }
  32. TJSONDateField = Class(TDateField)
  33. private
  34. FDateFormat: String;
  35. Published
  36. Property DateFormat : String Read FDateFormat Write FDateFormat;
  37. end;
  38. { TJSONTimeField }
  39. TJSONTimeField = Class(TTimeField)
  40. private
  41. FTimeFormat: String;
  42. Published
  43. Property TimeFormat : String Read FTimeFormat Write FTimeFormat;
  44. end;
  45. { TJSONDateTimeField }
  46. TJSONDateTimeField = Class(TDateTimeField)
  47. private
  48. FDateTimeFormat: String;
  49. Published
  50. Property DateTimeFormat : String Read FDateTimeFormat Write FDateTimeFormat;
  51. end;
  52. { TFieldComparer }
  53. TFieldComparer = Class
  54. Private
  55. FDesc: Boolean;
  56. FValue : JSValue;
  57. FField : TField;
  58. FOptions : TLocateOptions;
  59. FDataset : TBaseJSONDataset;
  60. Public
  61. Constructor Create(aDataset : TBaseJSONDataset; aField : TField; aValue : JSValue; aOptions : TLocateOptions);
  62. Function GetFieldValue(RowIndex : integer) : JSValue;
  63. Function CompareRows (RowIndex1,RowIndex2 : Integer) : Integer; virtual;
  64. // First value is always dataset value.
  65. Function Compare (RowIndex : Integer; aValue : JSValue) : Integer; virtual; abstract;
  66. Function Compare (RowIndex : Integer) : Integer; virtual;
  67. Property Value : JSValue read FValue Write FValue;
  68. Property Options : TLocateOptions Read FOptions Write FOptions;
  69. Property Dataset : TBaseJSONDataset Read FDataset;
  70. Property Field : TField Read FField;
  71. Property Desc : Boolean Read FDesc Write FDesc;
  72. end;
  73. TFieldComparerClass = Class of TFieldComparer;
  74. { TStringFieldComparer }
  75. TStringFieldComparer = Class (TFieldComparer)
  76. Function Compare (RowIndex : Integer; aValue : JSValue) : Integer; override;
  77. end;
  78. { TNativeIntFieldComparer }
  79. TNativeIntFieldComparer = Class (TFieldComparer)
  80. Function Compare (RowIndex : Integer; aValue : JSValue) : Integer; override;
  81. end;
  82. { TBooleanFieldComparer }
  83. TBooleanFieldComparer = Class (TFieldComparer)
  84. Function Compare (RowIndex : Integer; aValue : JSValue) : Integer; override;
  85. end;
  86. { TDateTimeFieldComparer }
  87. TDateTimeFieldComparer = Class (TFieldComparer)
  88. Function Compare (RowIndex : Integer; aValue : JSValue) : Integer; override;
  89. end;
  90. { TFloatFieldComparer }
  91. TFloatFieldComparer = Class (TFieldComparer)
  92. Function Compare (RowIndex : Integer; aValue : JSValue) : Integer; override;
  93. end;
  94. { TRecordComparer }
  95. TRecordComparer = class
  96. private
  97. FDataset: TBaseJSONDataset;
  98. FIndexBased: Boolean;
  99. FItems : Array of TFieldComparer;
  100. FOptions: TLocateOptions;
  101. FValues: TJSValueDynArray;
  102. function GetFieldComparer(Index : Integer): TFieldComparer;
  103. Protected
  104. procedure ConstructItems(aFields: String); virtual;
  105. function DataTypeToComparerClass(aFieldType: TFieldType): TFieldComparerClass;
  106. Function Compare(aRowindex : integer) : Integer;
  107. Function CompareRows(aRowindex1,aRowIndex2 : integer) : Integer;
  108. procedure updateFromIndex(aIndex : TJSONIndexDef); virtual;
  109. Public
  110. Constructor Create(aDataset : TBaseJSONDataset; aFields : String; aValues : JSValue; aOptions : TLocateOptions);
  111. Constructor Create(aDataset : TBaseJSONDataset; aIndex : TJSONIndexDef);
  112. Destructor Destroy; override;
  113. Property Dataset : TBaseJSONDataset Read FDataset;
  114. property Items [Index : Integer] : TFieldComparer Read GetFieldComparer;
  115. Property Options : TLocateOptions Read FOptions Write FOptions;
  116. Property Values : TJSValueDynArray Read FValues;
  117. Property IndexBased : Boolean Read FIndexBased;
  118. end;
  119. TRecordComparerClass = Class of TRecordComparer;
  120. { TBaseJSONDataSet }
  121. { TJSONIndex }
  122. TJSONIndex = Class
  123. FList : TJSArray; // Indexes of elements in FRows.
  124. FRows : TJSArray;
  125. FDataset : TBaseJSONDataset;
  126. private
  127. function GetRecordIndex(aListIndex : Integer): NativeInt;
  128. protected
  129. Function GetCount: Integer; virtual;
  130. Procedure CreateIndex; Virtual; abstract;
  131. Property List : TJSArray Read FList;
  132. Property Rows : TJSArray Read FRows;
  133. Property Dataset : TBaseJSONDataset Read FDataset;
  134. Public
  135. Constructor Create(aDataset: TBaseJSONDataset; aRows : TJSArray); reintroduce;
  136. // Append remainder of FRows to FList.
  137. Procedure AppendToIndex; virtual; abstract;
  138. // Delete aListIndex from list, not from row. Return Recordindex of deleted record.
  139. Function Delete(aListIndex : Integer) : Integer; virtual;
  140. // Append aRecordIndex to list. Return ListIndex of appended record.
  141. Function Append(aRecordIndex : Integer) : Integer; virtual; abstract;
  142. // Insert record into list. By default, this does an append. Return ListIndex of inserted record
  143. Function Insert(aCurrentIndex{%H-}, aRecordIndex : Integer) : Integer; virtual;
  144. // Record at index aCurrentIndex has changed. Update index and return new listindex.
  145. Function Update(aRecordIndex : Integer) : Integer; virtual; abstract;
  146. // Find list index for Record at index aCurrentIndex. Return -1 if not found.
  147. Function FindRecord(aRecordIndex : Integer) : Integer; virtual; abstract;
  148. // index of record in FRows based on aListIndex in List.
  149. Property RecordIndex[aListIndex : Integer] : NativeInt Read GetRecordIndex;
  150. // Number of records in index. This can differ from FRows, e.g. when filtering.
  151. Property Count : Integer Read GetCount;
  152. end;
  153. { TDefaultJSONIndex }
  154. TDefaultJSONIndex = Class(TJSONIndex)
  155. public
  156. Procedure CreateIndex; override;
  157. Procedure AppendToIndex; override;
  158. Function Append(aRecordIndex : Integer) : Integer; override;
  159. Function Insert(aCurrentIndex, aRecordIndex : Integer) : Integer; override;
  160. Function FindRecord(aRecordIndex : Integer) : Integer; override;
  161. Function Update(aRecordIndex : Integer) : Integer; override;
  162. end;
  163. { TSortedJSONIndex }
  164. TSortedJSONIndex = Class(TJSONIndex)
  165. Private
  166. FComparer : TRecordComparer;
  167. FUnique: Boolean;
  168. function FindPos(aRecordIndex: Integer): Integer;
  169. function MergeSort(aList: TJSArray): TJSArray;
  170. Protected
  171. Property Comparer : TRecordComparer Read FComparer Write FComparer;
  172. public
  173. Destructor Destroy; override;
  174. procedure CreateComparer(aIndex: TJSONIndexDef);
  175. Procedure CreateIndex; override;
  176. Procedure AppendToIndex; override;
  177. Function Append(aRecordIndex : Integer) : Integer; override;
  178. Function FindRecord(aRecordIndex : Integer) : Integer; override;
  179. Function Update(aRecordIndex : Integer) : Integer; override;
  180. Property Unique : Boolean Read FUnique Write FUnique;
  181. end;
  182. { TJSONIndexDef }
  183. TJSONIndexDef = class(TIndexDef)
  184. Private
  185. FIndex : TSortedJSONIndex;
  186. Protected
  187. Property Index : TSortedJSONIndex Read FIndex Write FIndex;
  188. Public
  189. Procedure BuildIndex(aDataset : TBaseJSONDataset);
  190. end;
  191. { TJSONIndexDefs }
  192. TJSONIndexDefs = Class(TIndexDefs)
  193. private
  194. function GetD(aIndex : Integer): TJSONIndexDef;
  195. procedure SetD(aIndex : Integer; AValue: TJSONIndexDef);
  196. Public
  197. Function AddJSONIndexDef: TJSONIndexDef;
  198. Property Defs[aIndex : Integer] : TJSONIndexDef Read GetD Write SetD; default;
  199. end;
  200. // basic JSON dataset. Does nothing ExtJS specific.
  201. TBaseJSONDataSet = class (TDataSet)
  202. private
  203. FActiveIndex: String;
  204. FIndexes: TJSONIndexDefs;
  205. FMUS: Boolean;
  206. FOwnsData : Boolean;
  207. FDefaultIndex : TJSONIndex; // Default index, built from array
  208. FCurrentIndex : TJSONIndex; // Currently active index.
  209. FCurrent: Integer; // Record Index in the current IndexList
  210. // Possible metadata to configure fields from.
  211. FMetaData : TJSObject;
  212. // This will contain the rows.
  213. FRows : TJSArray;
  214. // Deleted rows
  215. FDeletedRows : TJSArray;
  216. FFieldMapper : TJSONFieldMapper;
  217. // When editing, this object is edited.
  218. FEditIdx : Integer;
  219. FEditRow : JSValue;
  220. // When filtering, this is the current row;
  221. FFilterRow : JSValue;
  222. FUseDateTimeFormatFields: Boolean;
  223. FRowType: TJSONRowType;
  224. FFilterExpression : TFPExpressionParser;
  225. function GetFilterField(const AName: String): TFPExpressionResult;
  226. procedure SetActiveIndex(AValue: String);
  227. procedure SetIndexes(AValue: TJSONIndexDefs);
  228. procedure SetMetaData(AValue: TJSObject);
  229. procedure SetRows(AValue: TJSArray);
  230. procedure SetRowType(AValue: TJSONRowType);
  231. protected
  232. // Determine filter value type based on field type
  233. function FieldTypeToExpressionType(aDataType: TFieldType): TResultType; virtual;
  234. // Callback for IsNull filter function.
  235. function GetFilterIsNull(const Args: TExprParameterArray): TFPExpressionResult; virtual;
  236. // Expression parser class. Override this to create a customized version.
  237. function FilterExpressionClass: TFPExpressionParserClass; virtual;
  238. // Create filter expression.
  239. function CreateFilterExpression: TFPExpressionParser; virtual;
  240. // Function called to check if current buffer should be accepted.
  241. function DoFilterRecord: Boolean; virtual;
  242. // Override this to return customized version.
  243. function CreateIndexDefs: TJSONIndexDefs; virtual;
  244. // override this to return a customized version if you are so inclined
  245. function RecordComparerClass: TRecordComparerClass; virtual;
  246. // Return index of Row in FRows matching keyfields/values. If not found, -1 is returned.
  247. function LocateRecordIndex(const KeyFields: string; const KeyValues: JSValue; Options: TLocateOptions): Integer; virtual;
  248. // dataset virtual methods
  249. function AllocRecordBuffer: TDataRecord; override;
  250. procedure FreeRecordBuffer(var Buffer: TDataRecord); override;
  251. procedure InternalInitRecord(var Buffer: TDataRecord); override;
  252. function GetRecord(Var Buffer: TDataRecord; GetMode: TGetMode; DoCheck{%H-}: Boolean): TGetResult; override;
  253. function GetRecordSize: Word; override;
  254. procedure AddToRows(AValue: TJSArray);
  255. procedure InternalClose; override;
  256. procedure InternalDelete; override;
  257. procedure InternalFirst; override;
  258. procedure InternalLast; override;
  259. procedure InternalOpen; override;
  260. procedure InternalPost; override;
  261. procedure InternalInsert; override;
  262. procedure InternalEdit; override;
  263. procedure InternalCancel; override;
  264. procedure InternalInitFieldDefs; override;
  265. procedure InternalSetToRecord(Buffer: TDataRecord); override;
  266. procedure SetFilterText(const Value: string); override;
  267. procedure SetFiltered(Value: Boolean); override;
  268. function GetFieldClass(FieldType: TFieldType): TFieldClass; override;
  269. function IsCursorOpen: Boolean; override;
  270. // Bookmark operations
  271. procedure GetBookmarkData(Buffer: TDataRecord; var Data: TBookmark); override;
  272. function GetBookmarkFlag(Buffer: TDataRecord): TBookmarkFlag; override;
  273. procedure InternalGotoBookmark(ABookmark: TBookmark); override;
  274. procedure SetBookmarkFlag(Var Buffer: TDataRecord; Value: TBookmarkFlag); override;
  275. procedure SetBookmarkData(Var Buffer: TDataRecord; Data: TBookmark); override;
  276. function GetRecordCount: Integer; override;
  277. procedure SetRecNo(Value: Integer); override;
  278. function GetRecNo: Integer; override;
  279. Protected
  280. // New methods.
  281. // Build all sorted indexes. Default index is not built.
  282. Procedure BuildIndexes;
  283. // Called when dataset is closed. If OwnsData is true, metadata and rows are freed.
  284. Procedure FreeData; virtual;
  285. // Fill default list.
  286. procedure AppendToIndexes; virtual;
  287. Procedure CreateIndexes; virtual;
  288. // Convert MetaData object to FieldDefs.
  289. Procedure MetaDataToFieldDefs; virtual; abstract;
  290. // Initialize Date/Time info in all date/time fields. Called during InternalOpen
  291. procedure InitDateTimeFields; virtual;
  292. // Convert JSON date S to DateTime for Field F
  293. function ConvertDateTimeField(S: String; F: TField): TDateTime; virtual;
  294. // Format JSON date to from DT for Field F
  295. function FormatDateTimeField(DT : TDateTime; F: TField): String; virtual;
  296. // Create fieldmapper. A descendent MUST implement this.
  297. Function CreateFieldMapper : TJSONFieldMapper; virtual; abstract;
  298. // If True, then the dataset will free MetaData and FRows when it is closed.
  299. Property OwnsData : Boolean Read FownsData Write FOwnsData;
  300. // set to true if unknown field types should be handled as string fields.
  301. Property MapUnknownToStringType : Boolean Read FMUS Write FMUS;
  302. // Metadata
  303. Property MetaData : TJSObject Read FMetaData Write SetMetaData;
  304. // Rows
  305. Property Rows : TJSArray Read FRows Write SetRows;
  306. // RowType
  307. Property RowType : TJSONRowType Read FRowType Write SetRowType;
  308. // Fieldmapper
  309. Property FieldMapper : TJSONFieldMapper Read FFieldMapper;
  310. // FieldClass
  311. Property UseDateTimeFormatFields : Boolean Read FUseDateTimeFormatFields Write FUseDateTimeFormatFields;
  312. // Indexes
  313. Property Indexes : TJSONIndexDefs Read FIndexes Write SetIndexes;
  314. // Active index name. Set to empty for default index.
  315. Property ActiveIndex : String Read FActiveIndex Write SetActiveIndex;
  316. public
  317. constructor Create (AOwner: TComponent); override;
  318. destructor Destroy; override;
  319. function Locate(const KeyFields: string; const KeyValues: JSValue; Options: TLocateOptions): boolean; override;
  320. function Lookup(const KeyFields: string; const KeyValues: JSValue; const ResultFields: string): JSValue; override;
  321. function GetFieldData(Field: TField; Buffer: TDatarecord): JSValue; override;
  322. procedure SetFieldData(Field: TField; var Buffer{%H-}: TDatarecord; AValue : JSValue); override;
  323. function BookmarkValid(ABookmark: TBookmark): Boolean; override;
  324. function CompareBookmarks(Bookmark1, Bookmark2: TBookmark): Longint; override;
  325. end;
  326. TJSONDataset = Class(TBaseJSONDataset)
  327. published
  328. Property FieldDefs;
  329. Property RowType;
  330. Property UseDateTimeFormatFields;
  331. Property Indexes;
  332. Property ActiveIndex;
  333. property Active;
  334. property BeforeOpen;
  335. property AfterOpen;
  336. property BeforeClose;
  337. property AfterClose;
  338. property BeforeInsert;
  339. property AfterInsert;
  340. property BeforeEdit;
  341. property AfterEdit;
  342. property BeforePost;
  343. property AfterPost;
  344. property BeforeCancel;
  345. property AfterCancel;
  346. property BeforeDelete;
  347. property AfterDelete;
  348. property BeforeScroll;
  349. property AfterScroll;
  350. property OnCalcFields;
  351. property OnDeleteError;
  352. property OnEditError;
  353. property OnFilterRecord;
  354. property OnNewRecord;
  355. property OnPostError;
  356. end;
  357. { TJSONObjectFieldMapper }
  358. // Fieldmapper to be used when the data is in an object
  359. TJSONObjectFieldMapper = Class(TJSONFieldMapper)
  360. Public
  361. procedure SetJSONDataForField(Const FieldName : String; FieldIndex{%H-} : Integer; Row,Data : JSValue); override;
  362. Function GetJSONDataForField(Const FieldName : String; FieldIndex{%H-} : Integer; Row : JSValue) : JSValue; override;
  363. Function CreateRow : JSValue; override;
  364. end;
  365. { TJSONArrayFieldMapper }
  366. // Fieldmapper to be used when the data is in an array
  367. TJSONArrayFieldMapper = Class(TJSONFieldMapper)
  368. Public
  369. procedure SetJSONDataForField(Const FieldName{%H-} : String; FieldIndex : Integer; Row,Data : JSValue); override;
  370. Function GetJSONDataForField(Const FieldName{%H-} : String; FieldIndex : Integer; Row : JSValue) : JSValue; override;
  371. Function CreateRow : JSValue; override;
  372. end;
  373. EJSONDataset = Class(EDatabaseError);
  374. implementation
  375. uses DateUtils;
  376. { TJSONIndexDef }
  377. procedure TJSONIndexDef.BuildIndex(aDataset : TBaseJSONDataset);
  378. begin
  379. if Findex=Nil then
  380. FIndex:=TSortedJSONIndex.Create(aDataset,aDataset.Rows);
  381. FIndex.CreateComparer(Self);
  382. FIndex.CreateIndex;
  383. end;
  384. { TJSONIndexDefs }
  385. function TJSONIndexDefs.GetD(aIndex : Integer): TJSONIndexDef;
  386. begin
  387. Result:=Items[aIndex] as TJSONIndexDef;
  388. end;
  389. procedure TJSONIndexDefs.SetD(aIndex : Integer; AValue: TJSONIndexDef);
  390. begin
  391. Items[aIndex]:=aValue;
  392. end;
  393. function TJSONIndexDefs.AddJSONIndexDef: TJSONIndexDef;
  394. begin
  395. Result:=Add as TJSONIndexDef;
  396. end;
  397. { TSortedJSONIndex }
  398. Function TSortedJSONIndex.MergeSort(aList : TJSArray) : TJSArray;
  399. Var
  400. temp : TJSArray;
  401. l,p,q,e,tail : integer;
  402. insize, nmerges, psize, qsize : Integer;
  403. begin
  404. if aList=Nil then
  405. Exit(Nil);
  406. L:=aList.length;
  407. Result:=TJSArray.new(l);
  408. if L=0 then exit;
  409. insize:=1;
  410. Repeat
  411. p:=0;
  412. Tail:=0;
  413. nmerges := 0; // count number of merges we do in this pass
  414. while (p<L) do
  415. begin
  416. Inc(nmerges); { there exists a merge to be done }
  417. { step `insize' places along from p }
  418. pSize:=L-P;
  419. if Insize<pSize then
  420. pSize:=InSize;
  421. Q:=P+pSize;
  422. qsize:=insize;
  423. //* now we have two lists; merge them */
  424. while (psize>0) or ((qsize > 0) and (Q<L)) do
  425. begin // /* decide whether next element of merge comes from p or q */
  426. if (psize=0) then
  427. begin // * p is empty; e must come from q. */
  428. e := q; Inc(q); Dec(qsize);
  429. end
  430. else if ((qsize = 0) or (q>=L)) then
  431. begin // * q is empty; e must come from p. */
  432. e := p; Inc(p); Dec(psize);
  433. end
  434. else if (FComparer.CompareRows(Integer(aList[p]),Integer(aList[q])) <= 0) then
  435. begin // * First element of p is lower (or same); * e must come from p. */
  436. e:=p; inc(p); Dec(psize);
  437. end
  438. else
  439. begin // * First element of q is lower; e must come from q. */
  440. e := q; Inc(q); Dec(qsize);
  441. end;
  442. Result[Tail]:=aList[e];
  443. Inc(tail);
  444. end;
  445. p:=q;
  446. end;
  447. // * If we have done only one merge, we're finished. */
  448. if (nmerges <= 1) then //* allow for nmerges==0, the empty list case */
  449. exit;
  450. // * Otherwise repeat, merging lists twice the size */
  451. InSize:=Insize * 2;
  452. // Swap lists for next round.
  453. Temp:=Result;
  454. Result:=aList;
  455. aList:=Temp;
  456. until false;
  457. end;
  458. destructor TSortedJSONIndex.Destroy;
  459. begin
  460. FreeAndNil(FComparer);
  461. Inherited;
  462. end;
  463. procedure TSortedJSONIndex.CreateComparer(aIndex: TJSONIndexDef);
  464. begin
  465. FreeAndNil(FComparer);
  466. FComparer:=TRecordComparer.Create(Dataset,aindex);
  467. end;
  468. procedure TSortedJSONIndex.CreateIndex;
  469. Var
  470. Lst : TJSArray;
  471. Len : Integer;
  472. begin
  473. // CreateIndex is called during constructor. We cannot build index then, so we exit
  474. if FComparer=Nil then
  475. exit;
  476. Len:=FRows.Length-1;
  477. // Temp list, mergsort destroys list
  478. Lst:=TJSArray.New(Len+1);
  479. While Len>=0 do
  480. begin
  481. Lst[Len]:=Len;
  482. Dec(Len);
  483. end;
  484. FList:=MergeSort(Lst);
  485. end;
  486. procedure TSortedJSONIndex.AppendToIndex;
  487. begin
  488. // In theory, we could sort the rest of the list, and then merge the 2 sublists.
  489. CreateIndex;
  490. end;
  491. function TSortedJSONIndex.FindPos(aRecordIndex: Integer): Integer;
  492. Var
  493. L,R,I, CompareRes : Integer;
  494. begin
  495. if not Assigned(FComparer) then
  496. exit;
  497. L := 0;
  498. R := Count - 1;
  499. while (L<=R) do
  500. begin
  501. I := L + (R - L) div 2;
  502. CompareRes := FComparer.CompareRows(aRecordIndex, Integer(Flist[I]));
  503. if (CompareRes>0) then
  504. L := I+1
  505. else
  506. begin
  507. R := I-1;
  508. if (CompareRes=0) then
  509. begin
  510. if Unique then
  511. L := I; // forces end of while loop
  512. end;
  513. end;
  514. end;
  515. Result:=L;
  516. end;
  517. function TSortedJSONIndex.Append(aRecordIndex: Integer): Integer;
  518. begin
  519. Result:=FindPos(aRecordIndex);
  520. // insert in list
  521. FList.Splice(Result,0,aRecordIndex);
  522. end;
  523. function TSortedJSONIndex.FindRecord(aRecordIndex: Integer): Integer;
  524. begin
  525. Result:=FList.indexOf(aRecordIndex);
  526. end;
  527. function TSortedJSONIndex.Update(aRecordIndex: Integer): Integer;
  528. Var
  529. aCurrentIndex : Integer;
  530. begin
  531. // Old pos
  532. aCurrentIndex:=FindRecord(aRecordIndex);
  533. // New pos
  534. Result:=FindPos(aRecordIndex);
  535. if Result<>aCurrentIndex then
  536. FList.Splice(Result,0,FList.Splice(aCurrentIndex,1)[0])
  537. end;
  538. { TFloatFieldComparer }
  539. function TFloatFieldComparer.Compare(RowIndex: Integer; aValue: JSValue): Integer;
  540. var
  541. D1,D2 : Double;
  542. begin
  543. D1:=Double(GetFieldValue(Rowindex));
  544. D2:=Double(aValue);
  545. Result:=Round(D1-D2);
  546. end;
  547. { TDateTimeFieldComparer }
  548. function TDateTimeFieldComparer.Compare(RowIndex: Integer; aValue: JSValue): Integer;
  549. var
  550. D1,D2 : TDateTime;
  551. begin
  552. D1:=Dataset.ConvertDateTimeField(String(GetFieldValue(Rowindex)),Self.Field);
  553. D2:=TDateTime(aValue);
  554. Result:=Round(D1-D2);
  555. end;
  556. { TBooleanFieldComparer }
  557. function TBooleanFieldComparer.Compare(RowIndex: Integer; aValue: JSValue): Integer;
  558. var
  559. B1,B2 : Boolean;
  560. begin
  561. B1:=Boolean(GetFieldValue(Rowindex));
  562. B2:=Boolean(aValue);
  563. Result:=Ord(B1)-Ord(B2);
  564. end;
  565. { TNativeIntFieldComparer }
  566. function TNativeIntFieldComparer.Compare(RowIndex: Integer; aValue: JSValue): Integer;
  567. var
  568. I1,I2 : NativeInt;
  569. begin
  570. I1:=NativeInt(GetFieldValue(Rowindex));
  571. I2:=NativeInt(aValue);
  572. Result:=I1-I2;
  573. end;
  574. { TStringFieldComparer }
  575. function TStringFieldComparer.Compare(RowIndex: Integer; aValue: JSValue): Integer;
  576. var
  577. S1,S2 : String;
  578. begin
  579. S1:=String(GetFieldValue(Rowindex));
  580. S2:=String(aValue);
  581. if loPartialKey in Options then
  582. S1:=Copy(S1,1,Length(S2));
  583. if loCaseInsensitive in options then
  584. Result := CompareText(S1,S2)
  585. else
  586. Result := CompareStr(S1,S2);
  587. end;
  588. { TFieldComparer }
  589. constructor TFieldComparer.Create(aDataset: TBaseJSONDataset; aField: TField; aValue: JSValue; aOptions: TLocateOptions);
  590. begin
  591. FField:=AField;
  592. FValue:=aValue;
  593. FOptions:=aOptions;
  594. FDataset:=aDataset;
  595. end;
  596. function TFieldComparer.GetFieldValue(RowIndex: integer): JSValue;
  597. begin
  598. Result:=FDataset.FieldMapper.GetJSONDataForField(FField,FDataset.FRows[Rowindex]);
  599. end;
  600. function TFieldComparer.CompareRows(RowIndex1, RowIndex2: Integer): Integer;
  601. begin
  602. Result:=Compare(RowIndex1,GetFieldValue(RowIndex2));
  603. end;
  604. function TFieldComparer.Compare(RowIndex: Integer): Integer;
  605. begin
  606. Result:=Compare(RowIndex,FValue);
  607. end;
  608. { TRecordComparer }
  609. function TRecordComparer.GetFieldComparer(Index: Integer): TFieldComparer;
  610. begin
  611. if (Index<0) or (Index>=Length(Fitems)) then
  612. Raise EListError.CreateFmt('Index out of bounds: %d not in [%d,%d]',[Index,0,Length(Fitems)-1]);
  613. Result:=Items[Index];
  614. end;
  615. procedure TRecordComparer.ConstructItems(aFields : String);
  616. Var
  617. L : TFPlist;
  618. FCC : TFieldComparerClass;
  619. F : TField;
  620. I : Integer;
  621. begin
  622. L:=TFPList.Create;
  623. try
  624. Dataset.GetFieldList(L,aFields);
  625. if Not Indexbased and (L.Count<>Length(FValues)) then
  626. Raise EDatabaseError.CreateFmt('Array of values has different length (%d) from array of fields (%d)',[Length(FValues), L.Count]);
  627. SetLength(FItems,L.Count);
  628. For I:=0 to L.Count-1 do
  629. begin
  630. F:=TField(L[i]);
  631. FCC:=DataTypeToComparerClass(F.DataType);
  632. If FCC=Nil then
  633. Raise EDatabaseError.CreateFmt('Cannot locate on field %s of type %s)',[F.FieldName,GetEnumName(TypeInfo(TFieldType),Ord(F.DataType))]);
  634. if IndexBased then
  635. Fitems[i]:=FCC.Create(FDataset,F,Null,FOptions)
  636. else
  637. Fitems[i]:=FCC.Create(FDataset,F,FValues[i],FOptions);
  638. end;
  639. finally
  640. L.Free;
  641. end;
  642. end;
  643. function TRecordComparer.DataTypeToComparerClass(aFieldType: TFieldType): TFieldComparerClass;
  644. begin
  645. Case aFieldType of
  646. ftMemo, ftFixedChar,ftString :
  647. Result:=TStringFieldComparer;
  648. ftAutoInc, ftInteger, ftLargeInt:
  649. Result:=TNativeIntFieldComparer;
  650. ftBoolean:
  651. Result:=TBooleanFieldComparer;
  652. ftFloat:
  653. Result:=TFloatFieldComparer;
  654. ftDate, ftTime, ftDateTime:
  655. Result:=TDateTimeFieldComparer;
  656. else
  657. result:=Nil;
  658. end;
  659. end;
  660. function TRecordComparer.Compare(aRowindex: integer): Integer;
  661. Var
  662. I,L : Integer;
  663. begin
  664. Result:=0;
  665. I:=0;
  666. L:=Length(FItems);
  667. While (Result=0) and (I<L) do
  668. begin
  669. Result:=Fitems[i].Compare(aRowindex);
  670. Inc(I);
  671. end;
  672. end;
  673. function TRecordComparer.CompareRows(aRowindex1, aRowIndex2: integer): Integer;
  674. Var
  675. I,L : Integer;
  676. begin
  677. Result:=0;
  678. I:=0;
  679. L:=Length(FItems);
  680. While (Result=0) and (I<L) do
  681. begin
  682. Result:=Fitems[i].CompareRows(aRowindex1,aRowIndex2);
  683. if (Result<>0) and Fitems[i].Desc then
  684. Result:=-Result;
  685. Inc(I);
  686. end;
  687. end;
  688. procedure TRecordComparer.updateFromIndex(aIndex: TJSONIndexDef);
  689. Var
  690. L : TFPList;
  691. I : Integer;
  692. begin
  693. L:=TFPList.Create;
  694. try
  695. if (aIndex.CaseInsFields<>'') then
  696. begin
  697. Dataset.GetFieldList(L,aIndex.CaseInsFields);
  698. for I:=0 to Length(FItems)-1 do
  699. if L.IndexOf(FItems[i].Field)<>-1 then
  700. Fitems[i].Options:=Fitems[i].Options+[loCaseInsensitive];
  701. end;
  702. L.Clear;
  703. Dataset.GetFieldList(L,aIndex.DescFields);
  704. for I:=0 to Length(FItems)-1 do
  705. Fitems[i].Desc:=(ixDescending in aIndex.Options) or (L.IndexOf(FItems[i].Field)<>-1);
  706. finally
  707. L.Free;
  708. end;
  709. end;
  710. constructor TRecordComparer.Create(aDataset: TBaseJSONDataset; aFields: String; aValues: JSValue; aOptions: TLocateOptions);
  711. begin
  712. FDataset:=aDataset;
  713. if isArray(aValues) then
  714. FValues:=TJSValueDynArray(aValues)
  715. else
  716. begin
  717. SetLength(FValues,1);
  718. FValues[0]:=Avalues;
  719. end;
  720. Foptions:=aOptions;
  721. ConstructItems(aFields);
  722. end;
  723. constructor TRecordComparer.Create(aDataset: TBaseJSONDataset; aIndex: TJSONIndexDef);
  724. begin
  725. FDataset:=aDataset;
  726. FIndexBased:=True;
  727. if ixCaseInsensitive in aIndex.Options then
  728. FOptions:=[loCaseInsensitive];
  729. ConstructItems(aIndex.Fields);
  730. UpdateFromIndex(aIndex);
  731. end;
  732. destructor TRecordComparer.Destroy;
  733. Var
  734. I : Integer;
  735. begin
  736. For I:=0 to Length(FItems)-1 do
  737. FItems[i].Free;
  738. inherited Destroy;
  739. end;
  740. { TDefaultJSONIndex }
  741. procedure TDefaultJSONIndex.CreateIndex;
  742. Var
  743. I : Integer;
  744. begin
  745. For I:=0 to FRows.length-1 do
  746. FList[i]:=I;
  747. end;
  748. procedure TDefaultJSONIndex.AppendToIndex;
  749. Var
  750. I,L : Integer;
  751. begin
  752. L:=FList.Length;
  753. FList.Length:=FRows.Length;
  754. For I:=L to FRows.Length-1 do
  755. FList[i]:=I;
  756. end;
  757. function TDefaultJSONIndex.Append(aRecordIndex: Integer): Integer;
  758. begin
  759. Result:=FList.Push(aRecordIndex)-1;
  760. end;
  761. function TDefaultJSONIndex.Insert(aCurrentIndex, aRecordIndex: Integer
  762. ): Integer;
  763. begin
  764. FList.splice(aCurrentIndex, 0, aRecordIndex);
  765. Result:=aCurrentIndex;
  766. end;
  767. function TDefaultJSONIndex.FindRecord(aRecordIndex: Integer): Integer;
  768. begin
  769. Result:=FList.indexOf(aRecordIndex);
  770. end;
  771. function TDefaultJSONIndex.Update(aRecordIndex: Integer
  772. ): Integer;
  773. begin
  774. Result:=aRecordIndex;
  775. end;
  776. { TJSONIndex }
  777. constructor TJSONIndex.Create(aDataset: TBaseJSONDataset; aRows: TJSArray);
  778. begin
  779. FRows:=aRows;
  780. FList:=TJSArray.New(FRows.length);
  781. FDataset:=aDataset;
  782. CreateIndex;
  783. end;
  784. function TJSONIndex.Delete(aListIndex: Integer): Integer;
  785. Var
  786. a : TJSArray;
  787. begin
  788. A:=FList.Splice(aListIndex,1);
  789. If a.Length>0 then
  790. Result:=Integer(A[0])
  791. else
  792. Result:=-1;
  793. end;
  794. function TJSONIndex.Insert(aCurrentIndex, aRecordIndex: Integer): Integer;
  795. begin
  796. Result:=Append(aRecordIndex);
  797. end;
  798. function TJSONIndex.GetCount: Integer;
  799. begin
  800. Result:=FList.Length;
  801. end;
  802. function TJSONIndex.GetRecordIndex(aListIndex : Integer): NativeInt;
  803. begin
  804. if isUndefined(FList[aListIndex]) then
  805. Result:=-1
  806. else
  807. Result:=NativeInt(FList[aListIndex]);
  808. end;
  809. { TJSONFieldMapper }
  810. function TJSONFieldMapper.GetJSONDataForField(F: TField; Row: JSValue ): JSValue;
  811. begin
  812. // This supposes that Index is correct, i.e. the field positions have not been changed.
  813. Result:=GetJSONDataForField(F.FieldName,F.Index,Row);
  814. end;
  815. procedure TJSONFieldMapper.SetJSONDataForField(F: TField; Row,Data: JSValue);
  816. begin
  817. SetJSONDataForField(F.FieldName,F.Index,Row,Data);
  818. end;
  819. { TJSONArrayFieldMapper }
  820. procedure TJSONArrayFieldMapper.SetJSONDataForField(const FieldName: String;
  821. FieldIndex: Integer; Row, Data: JSValue);
  822. begin
  823. TJSValueDynArray(Row)[FieldIndex]:=Data;
  824. end;
  825. function TJSONArrayFieldMapper.GetJSONDataForField(Const FieldName: String;
  826. FieldIndex: Integer; Row: JSValue): JSValue;
  827. begin
  828. Result:=TJSValueDynArray(Row)[FieldIndex];
  829. end;
  830. function TJSONArrayFieldMapper.CreateRow: JSValue;
  831. begin
  832. Result:=TJSArray.New;
  833. end;
  834. { TJSONObjectFieldMapper }
  835. procedure TJSONObjectFieldMapper.SetJSONDataForField(const FieldName: String;
  836. FieldIndex: Integer; Row, Data: JSValue);
  837. begin
  838. TJSObject(Row).Properties[FieldName]:=Data;
  839. end;
  840. function TJSONObjectFieldMapper.GetJSONDataForField(const FieldName: String;
  841. FieldIndex: Integer; Row: JSValue): JSValue;
  842. begin
  843. Result:=TJSObject(Row).Properties[FieldName];
  844. end;
  845. function TJSONObjectFieldMapper.CreateRow: JSValue;
  846. begin
  847. Result:=TJSObject.New;
  848. end;
  849. procedure TBaseJSONDataSet.SetMetaData(AValue: TJSObject);
  850. begin
  851. CheckInActive;
  852. FMetaData:=AValue;
  853. end;
  854. procedure TBaseJSONDataSet.SetIndexes(AValue: TJSONIndexDefs);
  855. begin
  856. if FIndexes=AValue then Exit;
  857. FIndexes.Assign(aValue);
  858. if Active then
  859. BuildIndexes;
  860. end;
  861. procedure TBaseJSONDataSet.SetActiveIndex(AValue: String);
  862. Var
  863. Idx : TJSONIndexDef;
  864. begin
  865. if FActiveIndex=AValue then Exit;
  866. if (csLoading in ComponentState) then
  867. FActiveIndex:=AValue
  868. else
  869. begin
  870. if (AValue<>'') then
  871. Idx:=FIndexes.Find(aValue) as TJSONIndexDef
  872. else
  873. Idx:=nil;
  874. FActiveIndex:=AValue;
  875. if Not (csLoading in ComponentState) then
  876. if Idx=Nil then
  877. FCurrentIndex:=FDefaultIndex
  878. else
  879. begin
  880. if Idx.Index=Nil then
  881. Idx.BuildIndex(Self);
  882. FCurrentIndex:=Idx.Index;
  883. end;
  884. if Active then
  885. Resync([rmCenter]);
  886. end;
  887. end;
  888. procedure TBaseJSONDataSet.AddToRows(AValue: TJSArray);
  889. begin
  890. if FRows=Nil then
  891. FRows:=AValue
  892. else
  893. begin
  894. FRows:=FRows.Concat(AValue);
  895. AppendToIndexes;
  896. end;
  897. end;
  898. procedure TBaseJSONDataSet.SetRows(AValue: TJSArray);
  899. begin
  900. if AValue=FRows then exit;
  901. CheckInActive;
  902. FRows:=Nil;
  903. AddToRows(AValue);
  904. end;
  905. procedure TBaseJSONDataSet.SetRowType(AValue: TJSONRowType);
  906. begin
  907. if FRowType=AValue then Exit;
  908. CheckInactive;
  909. FRowType:=AValue;
  910. end;
  911. function TBaseJSONDataSet.AllocRecordBuffer: TDataRecord;
  912. begin
  913. Result.data:=TJSObject.New;
  914. Result.bookmark:=null;
  915. Result.state:=rsNew;
  916. end;
  917. // the next two are particularly ugly.
  918. procedure TBaseJSONDataSet.InternalInitRecord(var Buffer: TDataRecord);
  919. begin
  920. // Writeln('TBaseJSONDataSet.InternalInitRecord');
  921. Buffer.Data:=FFieldMapper.CreateRow;
  922. Buffer.bookmark:=null;
  923. Buffer.state:=rsNew;
  924. end;
  925. procedure TBaseJSONDataSet.FreeRecordBuffer (var Buffer: TDataRecord);
  926. begin
  927. Buffer.Data:=Null;
  928. Buffer.bookmark:=null;
  929. Buffer.state:=rsNew;
  930. end;
  931. procedure TBaseJSONDataSet.GetBookmarkData(Buffer: TDataRecord; var Data: TBookmark);
  932. begin
  933. Data.Data:=Buffer.bookmark;
  934. end;
  935. function TBaseJSONDataSet.GetBookmarkFlag(Buffer: TDataRecord): TBookmarkFlag;
  936. begin
  937. Result :=Buffer.BookmarkFlag;
  938. end;
  939. function TBaseJSONDataSet.GetRecNo: Integer;
  940. Var
  941. bkmIdx : Integer;
  942. begin
  943. bkmIdx:=Integer(ActiveBuffer.bookmark);
  944. Result:=FCurrentIndex.FindRecord(bkmIdx)+1;
  945. end;
  946. procedure TBaseJSONDataSet.InternalInitFieldDefs;
  947. begin
  948. If Assigned(FMetaData) then
  949. MetaDataToFieldDefs;
  950. if (FieldDefs.Count=0) then
  951. Raise EJSONDataset.Create('No fields found');
  952. end;
  953. procedure TBaseJSONDataSet.FreeData;
  954. begin
  955. If FOwnsData then
  956. begin
  957. FRows:=Nil;
  958. FMetaData:=Nil;
  959. end;
  960. if (FCurrentIndex<>FDefaultIndex) then
  961. FreeAndNil(FCurrentIndex)
  962. else
  963. FCurrentIndex:=Nil;
  964. FreeAndNil(FDefaultindex);
  965. FreeAndNil(FFieldMapper);
  966. FCurrentIndex:=Nil;
  967. FDeletedRows:=Nil;
  968. end;
  969. procedure TBaseJSONDataSet.AppendToIndexes;
  970. begin
  971. FDefaultIndex.AppendToIndex;
  972. end;
  973. procedure TBaseJSONDataSet.CreateIndexes;
  974. begin
  975. FDefaultIndex:=TDefaultJSONIndex.Create(Self,FRows);
  976. AppendToIndexes;
  977. FCurrentIndex:=FDefaultIndex;
  978. end;
  979. function TBaseJSONDataSet.FilterExpressionClass : TFPExpressionParserClass;
  980. begin
  981. Result:=TFPExpressionParser;
  982. end;
  983. function TBaseJSONDataSet.GetFilterIsNull(Const Args : TExprParameterArray) : TFPExpressionResult;
  984. begin
  985. Result.ResultType:=rtBoolean;
  986. Result.ResValue:=FieldByName(String(Args[0].resValue)).IsNull;
  987. end;
  988. function TBaseJSONDataSet.FieldTypeToExpressionType(aDataType : TFieldType) : TResultType;
  989. begin
  990. Case aDataType of
  991. ftMemo,
  992. ftFixedChar,
  993. ftString : Result:=rtString;
  994. ftInteger,
  995. ftAutoInc,
  996. ftLargeInt : Result:=rtInteger;
  997. ftBoolean : Result:=rtBoolean;
  998. ftFloat : Result:=rtFloat;
  999. ftDate,
  1000. ftTime,
  1001. ftDateTime : Result:=rtDateTime;
  1002. else
  1003. DatabaseErrorFmt('Fields of type %s are not supported in filter expressions.',[Fieldtypenames[aDataType]],Self);
  1004. end;
  1005. end;
  1006. function TBaseJSONDataSet.GetFilterField(Const AName : String) : TFPExpressionResult;
  1007. Var
  1008. F : TField;
  1009. C : Currency;
  1010. begin
  1011. F:=FieldByName(aName);
  1012. Result.resultType:=FieldTypeToExpressionType(F.DataType);
  1013. case Result.resultType of
  1014. rtBoolean : Result.resValue:=F.AsBoolean;
  1015. rtInteger : Result.resValue:=F.AsLargeInt;
  1016. rtFloat : Result.resValue:=F.AsFloat;
  1017. rtDateTime : Result.resValue:=F.AsDateTime;
  1018. rtString : Result.resValue:=F.AsString;
  1019. rtCurrency :
  1020. begin
  1021. C:=Currency(F.AsFloat);
  1022. Result.resValue:=C;
  1023. end;
  1024. end;
  1025. // Writeln('Filtering field ',aName,'value: ',result.resValue);
  1026. end;
  1027. function TBaseJSONDataSet.CreateFilterExpression : TFPExpressionParser;
  1028. Var
  1029. I : Integer;
  1030. begin
  1031. Result:=FilterExpressionClass.Create(Self);
  1032. for I:=0 to Fields.Count-1 do
  1033. Result.Identifiers.AddVariable(Fields[i].FieldName,FieldTypeToExpressionType(Fields[i].DataType),@GetFilterField);
  1034. Result.Identifiers.AddFunction('IsNull','B','S',@GetFilterIsNull);
  1035. Result.Expression:=Filter;
  1036. end;
  1037. function TBaseJSONDataSet.DoFilterRecord : Boolean;
  1038. Var
  1039. DS : TDatasetState;
  1040. begin
  1041. // Writeln('Filtering');
  1042. Result:=True;
  1043. DS:=SetTempState(dsFilter);
  1044. try
  1045. if Assigned(OnFilterRecord) then
  1046. begin
  1047. OnFilterRecord(Self,Result);
  1048. if Not Result then
  1049. Exit;
  1050. end;
  1051. if not Filtered or (Filter='') then
  1052. Exit;
  1053. if (FFilterExpression=Nil) then
  1054. FFilterExpression:=CreateFilterExpression;
  1055. Result:=FFilterExpression.AsBoolean;
  1056. finally
  1057. RestoreState(DS);
  1058. end;
  1059. end;
  1060. function TBaseJSONDataSet.GetRecord(Var Buffer: TDataRecord; GetMode: TGetMode; DoCheck: Boolean): TGetResult;
  1061. Var
  1062. BkmIdx : Integer;
  1063. recordAccepted : Boolean;
  1064. begin
  1065. Result := grOK; // default
  1066. Repeat
  1067. recordAccepted:=True;
  1068. case GetMode of
  1069. gmNext: // move on
  1070. if fCurrent < fCurrentIndex.Count - 1 then
  1071. Inc (fCurrent)
  1072. else
  1073. Result := grEOF; // end of file
  1074. gmPrior: // move back
  1075. if fCurrent > 0 then
  1076. Dec (fCurrent)
  1077. else
  1078. Result := grBOF; // begin of file
  1079. gmCurrent: // check if empty
  1080. if fCurrent >= fCurrentIndex.Count then
  1081. Result := grEOF;
  1082. end;
  1083. if Result = grOK then // read the data
  1084. begin
  1085. BkmIdx:=FCurrentIndex.RecordIndex[FCurrent];
  1086. Buffer.Data:=FRows[bkmIdx];
  1087. Buffer.BookmarkFlag := bfCurrent;
  1088. Buffer.Bookmark:=BkmIdx;
  1089. CalculateFields(Buffer);
  1090. if Filtered then
  1091. begin
  1092. FFilterRow:=Buffer.Data;
  1093. recordAccepted:=DoFilterRecord;
  1094. end;
  1095. end;
  1096. until recordAccepted;
  1097. end;
  1098. function TBaseJSONDataSet.GetRecordCount: Integer;
  1099. begin
  1100. Result:=FCurrentIndex.Count;
  1101. end;
  1102. function TBaseJSONDataSet.GetRecordSize: Word;
  1103. begin
  1104. Result := 0; // actual data without house-keeping
  1105. end;
  1106. procedure TBaseJSONDataSet.InternalClose;
  1107. begin
  1108. // disconnet and destroy field objects
  1109. BindFields (False);
  1110. if DefaultFields then
  1111. DestroyFields;
  1112. FreeData;
  1113. end;
  1114. procedure TBaseJSONDataSet.InternalDelete;
  1115. Var
  1116. Idx : Integer;
  1117. begin
  1118. Idx:=FCurrentIndex.Delete(FCurrent);
  1119. if (Idx<>-1) then
  1120. begin
  1121. // Add code here to Delete from other indexes as well.
  1122. // ...
  1123. // Add to array of deleted records.
  1124. if Not Assigned(FDeletedRows) then
  1125. FDeletedRows:=TJSArray.New(FRows[idx])
  1126. else
  1127. FDeletedRows.Push(FRows[Idx]);
  1128. FRows[Idx]:=Undefined;
  1129. end;
  1130. end;
  1131. procedure TBaseJSONDataSet.InternalFirst;
  1132. begin
  1133. FCurrent := -1;
  1134. end;
  1135. procedure TBaseJSONDataSet.InternalGotoBookmark(ABookmark: TBookmark);
  1136. begin
  1137. if isNumber(ABookmark.Data) then
  1138. FCurrent:=FCurrentIndex.FindRecord(Integer(ABookmark.Data));
  1139. // Writeln('Fcurrent', FCurrent,' from ',ABookmark.Data);
  1140. end;
  1141. procedure TBaseJSONDataSet.InternalInsert;
  1142. Var
  1143. I : Integer;
  1144. D : TFieldDef;
  1145. begin
  1146. // Writeln('TBaseJSONDataSet.InternalInsert');
  1147. FEditRow:=ActiveBuffer.Data;
  1148. For I:=0 to FieldDefs.Count-1 do
  1149. begin
  1150. D:=FieldDefs[i];
  1151. FFieldMapper.SetJSONDataForField(D.Name,D.Index,FEditRow,Null);
  1152. end;
  1153. end;
  1154. procedure TBaseJSONDataSet.InternalEdit;
  1155. begin
  1156. // Writeln('TBaseJSONDataSet.InternalEdit: ');
  1157. FEditIdx:=FCurrentIndex.RecordIndex[FCurrent];
  1158. if not isUndefined(Rows[FEditIdx]) then
  1159. FEditRow:=TJSJSON.parse(TJSJSON.stringify(Rows[FEditIdx]))
  1160. else
  1161. FEditRow:=TJSObject.new;
  1162. // Writeln('TBaseJSONDataSet.InternalEdit: ',FEditRow);
  1163. end;
  1164. procedure TBaseJSONDataSet.InternalCancel;
  1165. begin
  1166. FEditIdx:=-1;
  1167. FEditRow:=Nil;
  1168. end;
  1169. procedure TBaseJSONDataSet.InternalLast;
  1170. begin
  1171. // The first thing that will happen is a GetPrior Record.
  1172. FCurrent:=FCurrentIndex.Count;
  1173. end;
  1174. procedure TBaseJSONDataSet.InitDateTimeFields;
  1175. begin
  1176. // Do nothing
  1177. end;
  1178. procedure TBaseJSONDataSet.InternalOpen;
  1179. begin
  1180. FreeAndNil(FFieldMapper);
  1181. FFieldMapper:=CreateFieldMapper;
  1182. IF (FRows=Nil) then // opening from fielddefs ?
  1183. begin
  1184. FRows:=TJSArray.New;
  1185. OwnsData:=True;
  1186. end;
  1187. CreateIndexes;
  1188. InternalInitFieldDefs;
  1189. if DefaultFields then
  1190. CreateFields;
  1191. BindFields (True);
  1192. InitDateTimeFields;
  1193. FCurrent := -1;
  1194. end;
  1195. procedure TBaseJSONDataSet.InternalPost;
  1196. Var
  1197. I,NewCurrent,Idx : integer;
  1198. B : TBookmark;
  1199. begin
  1200. NewCurrent:=-1;
  1201. GetBookMarkData(ActiveBuffer,B);
  1202. if (State=dsInsert) then
  1203. begin // Insert or Append
  1204. Idx:=FRows.push(FEditRow)-1;
  1205. if GetBookMarkFlag(ActiveBuffer)=bfEOF then
  1206. begin // Append
  1207. FDefaultIndex.Append(Idx);
  1208. // Must replace this by updating all indexes
  1209. for I:=0 to FIndexes.Count-1 do
  1210. begin
  1211. NewCurrent:=FIndexes[i].Findex.Append(Idx);
  1212. if FIndexes[i].Findex<>FCurrentIndex then
  1213. NewCurrent:=-1;
  1214. end;
  1215. end
  1216. else // insert
  1217. begin
  1218. FCurrent:=FDefaultIndex.Insert(FCurrent,Idx);
  1219. for I:=0 to FIndexes.Count-1 do
  1220. begin
  1221. NewCurrent:=FIndexes[i].Findex.Append(Idx);
  1222. if FIndexes[i].Findex<>FCurrentIndex then
  1223. NewCurrent:=-1;
  1224. end;
  1225. end;
  1226. end
  1227. else
  1228. begin // Edit
  1229. if (FEditIdx=-1) then
  1230. DatabaseErrorFmt('Failed to retrieve record index for record %d',[FCurrent]);
  1231. // Update source record
  1232. Idx:=FEditIdx;
  1233. FRows[Idx]:=FEditRow;
  1234. FDefaultIndex.Update(Idx);
  1235. // Must replace this by updating all indexes.
  1236. // Note that this will change current index.
  1237. for I:=0 to FIndexes.Count-1 do
  1238. begin
  1239. // Determine old index.
  1240. NewCurrent:=FCurrentIndex.Update(Idx);
  1241. if FIndexes[i].Findex<>FCurrentIndex then
  1242. NewCurrent:=-1;
  1243. end;
  1244. end;
  1245. // We have an active index, set current to that index.
  1246. if NewCurrent<>-1 then
  1247. FCurrent:=NewCurrent;
  1248. FEditIdx:=-1;
  1249. FEditRow:=Nil;
  1250. end;
  1251. procedure TBaseJSONDataSet.InternalSetToRecord(Buffer: TDataRecord);
  1252. begin
  1253. FCurrent:=FCurrentIndex.FindRecord(Integer(Buffer.Bookmark));
  1254. end;
  1255. procedure TBaseJSONDataSet.SetFilterText(const Value: string);
  1256. begin
  1257. inherited SetFilterText(Value);
  1258. FreeAndNil(FFilterExpression);
  1259. if Active then
  1260. Resync([rmCenter]);
  1261. end;
  1262. procedure TBaseJSONDataSet.SetFiltered(Value: Boolean);
  1263. begin
  1264. inherited SetFiltered(Value);
  1265. FreeAndNil(FFilterExpression);
  1266. if Active then
  1267. Resync([rmCenter]);
  1268. end;
  1269. function TBaseJSONDataSet.GetFieldClass(FieldType: TFieldType): TFieldClass;
  1270. begin
  1271. If UseDateTimeFormatFields and (FieldType in [ftDate,ftDateTime,ftTime]) then
  1272. case FieldType of
  1273. ftDate : Result:=TJSONDateField;
  1274. ftDateTime : Result:=TJSONDateTimeField;
  1275. ftTime : Result:=TJSONTimeField;
  1276. end
  1277. else
  1278. Result:=inherited GetFieldClass(FieldType);
  1279. end;
  1280. function TBaseJSONDataSet.IsCursorOpen: Boolean;
  1281. begin
  1282. Result := Assigned(FDefaultIndex);
  1283. end;
  1284. function TBaseJSONDataSet.BookmarkValid(ABookmark: TBookmark): Boolean;
  1285. begin
  1286. Result:=isNumber(ABookmark.Data);
  1287. end;
  1288. procedure TBaseJSONDataSet.SetBookmarkData(var Buffer: TDataRecord; Data: TBookmark);
  1289. begin
  1290. Buffer.Bookmark:=Data.Data;
  1291. // Writeln('Set Bookmark from: ',Data.Data);
  1292. end;
  1293. function TBaseJSONDataSet.ConvertDateTimeField(S : String; F : TField) : TDateTime;
  1294. Var
  1295. Ptrn : string;
  1296. begin
  1297. Result:=0;
  1298. Ptrn:='';
  1299. Case F.DataType of
  1300. ftDate : if F is TJSONDateField then
  1301. Ptrn:=(F as TJSONDateField).DateFormat;
  1302. ftTime : if F is TJSONTimeField then
  1303. Ptrn:=(F as TJSONTimeField).TimeFormat;
  1304. ftDateTime : if F is TJSONDateTimeField then
  1305. Ptrn:=(F as TJSONDateTimeField).DateTimeFormat;
  1306. end;
  1307. If (Ptrn='') then
  1308. Case F.DataType of
  1309. ftDate : Result:=StrToDate(S);
  1310. ftTime : Result:=StrToTime(S);
  1311. ftDateTime : Result:=StrToDateTime(S);
  1312. end
  1313. else
  1314. begin
  1315. Result:=ScanDateTime(ptrn,S,1);
  1316. end;
  1317. end;
  1318. function TBaseJSONDataSet.FormatDateTimeField(DT: TDateTime; F: TField
  1319. ): String;
  1320. Var
  1321. Ptrn : string;
  1322. begin
  1323. Result:='';
  1324. Ptrn:='';
  1325. Case F.DataType of
  1326. ftDate : if F is TJSONDateField then
  1327. Ptrn:=TJSONDateField(F).DateFormat;
  1328. ftTime : if F is TJSONTimeField then
  1329. Ptrn:=TJSONTimeField(F).TimeFormat;
  1330. ftDateTime : if F is TJSONDateTimeField then
  1331. Ptrn:=TJSONDateTimeField(F).DateTimeFormat;
  1332. end;
  1333. If (Ptrn='') then
  1334. Case F.DataType of
  1335. ftDate : Result:=DateToStr(DT);
  1336. ftTime : Result:=TimeToStr(DT);
  1337. ftDateTime : Result:=DateTimeToStr(DT);
  1338. end
  1339. else
  1340. Result:=FormatDateTime(ptrn,DT);
  1341. end;
  1342. function TBaseJSONDataSet.GetFieldData(Field: TField; Buffer: TDatarecord): JSValue;
  1343. var
  1344. R : JSValue;
  1345. begin
  1346. if State in [dsCalcFields,dsInternalCalc] then
  1347. R:=CalcBuffer.data
  1348. else if (State=dsFilter) then
  1349. R:=FFilterRow
  1350. else if (FEditIdx=Buffer.Bookmark) then
  1351. begin
  1352. if State=dsOldValue then
  1353. R:=Buffer.data
  1354. else
  1355. R:=FEditRow
  1356. end
  1357. else
  1358. begin
  1359. if State=dsOldValue then
  1360. Exit(Null)
  1361. else
  1362. R:=Buffer.data;
  1363. end;
  1364. Result:=FFieldMapper.GetJSONDataForField(Field,R);
  1365. end;
  1366. procedure TBaseJSONDataSet.SetFieldData(Field: TField; var Buffer: TDatarecord; AValue : JSValue);
  1367. var
  1368. R : JSValue;
  1369. begin
  1370. if State in [dsCalcFields,dsInternalCalc] then
  1371. R:=CalcBuffer.Data
  1372. else
  1373. R:=FEditRow;
  1374. FFieldMapper.SetJSONDataForField(Field,R,AValue);
  1375. if not(State in [dsCalcFields, dsInternalCalc, dsFilter, dsNewValue]) then
  1376. DataEvent(deFieldChange, Field);
  1377. SetModified(True);
  1378. // FFieldMapper.SetJSONDataForField(Field,Buffer.Data,AValue);
  1379. end;
  1380. procedure TBaseJSONDataSet.SetBookmarkFlag(var Buffer: TDataRecord; Value: TBookmarkFlag);
  1381. begin
  1382. Buffer.BookmarkFlag := Value;
  1383. end;
  1384. function TBaseJSONDataSet.CompareBookmarks(Bookmark1, Bookmark2: TBookmark): Longint;
  1385. begin
  1386. if isNumber(Bookmark1.Data) and isNumber(Bookmark2.Data) then
  1387. Result := Integer(Bookmark2.Data) - Integer(Bookmark1.Data)
  1388. else
  1389. begin
  1390. if isNumber(Bookmark1.Data) then
  1391. Result := -1
  1392. else
  1393. if isNumber(Bookmark2.Data) then
  1394. Result := 1
  1395. else
  1396. Result := 0;
  1397. end;
  1398. end;
  1399. procedure TBaseJSONDataSet.SetRecNo(Value: Integer);
  1400. begin
  1401. if (Value < 1) or (Value > FCurrentIndex.Count) then
  1402. raise EJSONDataset.CreateFmt('%s: SetRecNo: index %d out of range',[Name,Value]);
  1403. FCurrent := Value - 1;
  1404. Resync([]);
  1405. DoAfterScroll;
  1406. end;
  1407. constructor TBaseJSONDataSet.Create(AOwner: TComponent);
  1408. begin
  1409. inherited;
  1410. FownsData:=True;
  1411. UseDateTimeFormatFields:=False;
  1412. FEditIdx:=-1;
  1413. FIndexes:=CreateIndexDefs;
  1414. end;
  1415. destructor TBaseJSONDataSet.Destroy;
  1416. begin
  1417. FreeAndNil(FFilterExpression);
  1418. FreeAndNil(FIndexes);
  1419. FEditIdx:=-1;
  1420. FreeData;
  1421. inherited;
  1422. end;
  1423. Function TBaseJSONDataSet.CreateIndexDefs : TJSONIndexDefs;
  1424. begin
  1425. Result:=TJSONIndexDefs.Create(Self,Self,TJSONIndexDef);
  1426. end;
  1427. procedure TBaseJSONDataSet.BuildIndexes;
  1428. Var
  1429. I : integer;
  1430. begin
  1431. For I:=0 to FIndexes.Count-1 do
  1432. FIndexes[i].BuildIndex(Self);
  1433. end;
  1434. function TBaseJSONDataSet.RecordComparerClass : TRecordComparerClass;
  1435. begin
  1436. Result:=TRecordComparer;
  1437. end;
  1438. function TBaseJSONDataSet.LocateRecordIndex(const KeyFields: string; const KeyValues: JSValue; Options: TLocateOptions): Integer;
  1439. Var
  1440. Comp : TRecordComparer;
  1441. RI,I : Integer;
  1442. begin
  1443. Result:=-1;
  1444. Comp:=RecordComparerClass.Create(Self,KeyFields,KeyValues,Options);
  1445. try
  1446. I:=FCurrent;
  1447. RI:=FCurrentIndex.GetRecordIndex(I);
  1448. While (Result=-1) and (RI<>-1) do
  1449. begin
  1450. if Comp.Compare(RI)=0 then
  1451. Result:=RI;
  1452. inc(I);
  1453. RI:=FCurrentIndex.GetRecordIndex(I);
  1454. end;
  1455. finally
  1456. Comp.Free;
  1457. end;
  1458. end;
  1459. function TBaseJSONDataSet.Locate(const KeyFields: string; const KeyValues: JSValue; Options: TLocateOptions): boolean;
  1460. Var
  1461. I : Integer;
  1462. BM : TBookMark;
  1463. begin
  1464. Result:=Inherited;
  1465. I:=LocateRecordIndex(KeyFields,KeyValues,Options);
  1466. Result:=I<>-1;
  1467. if Result then
  1468. begin
  1469. // Construct bookmark.
  1470. // Bookmark is always the index in the FRows array.
  1471. BM.Data:=I;
  1472. BM.Flag:=bfCurrent;
  1473. GotoBookMark(BM);
  1474. end;
  1475. end;
  1476. function TBaseJSONDataSet.Lookup(const KeyFields: string; const KeyValues: JSValue; const ResultFields: string): JSValue;
  1477. Var
  1478. RI,I : Integer;
  1479. l : TFPList;
  1480. Vals : TJSValueDynArray;
  1481. begin
  1482. Result:=Null;
  1483. l:=TFPList.Create;
  1484. try
  1485. GetFieldList(L,ResultFields);
  1486. Result:=inherited Lookup(KeyFields, KeyValues, ResultFields);
  1487. RI:=LocateRecordIndex(KeyFields,KeyValues,[]);
  1488. Result:=RI<>-1;
  1489. if Result then
  1490. begin
  1491. SetLength(Vals,L.Count);
  1492. For I:=0 to L.Count-1 do
  1493. Vals[i]:=FFieldMapper.GetJSONDataForField(TField(L[I]),FRows[RI]);
  1494. if L.Count=1 then
  1495. Result:=Vals[i]
  1496. else
  1497. Result:=Vals;
  1498. end;
  1499. finally
  1500. L.Free;
  1501. end;
  1502. end;
  1503. end.