jsondataset.pas 47 KB

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