fieldmap.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2022 by Michael van Canneyt and other members of the
  4. Free Pascal development team
  5. Field map implementation
  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. unit fieldmap;
  13. {$mode objfpc}
  14. {$H+}
  15. interface
  16. uses SysUtils,Classes, fmtBCD, db;
  17. { ---------------------------------------------------------------------
  18. TFieldMap
  19. ---------------------------------------------------------------------}
  20. type
  21. EFieldMap = Class(EDatabaseError);
  22. { TFieldMap }
  23. TFieldMap = Class(TObject)
  24. private
  25. FDataset: TDataset;
  26. FFreeDataset: Boolean;
  27. FOldOnOpen : TDataSetNotifyEvent;
  28. Protected
  29. Procedure DoOnOpen(Sender : TDataset);
  30. Function FindField(const FN : String) : TField;
  31. Function FieldByName(const FN : String) : TField;
  32. Public
  33. Constructor Create(ADataset : TDataset; HookOnOpen : Boolean = False);
  34. Destructor Destroy; override;
  35. Procedure InitFields; virtual; abstract;
  36. Procedure LoadObject(AObject : TObject); virtual;
  37. Function GetFromField(F : TField; ADefault : TBCD) : TBCD; overload;
  38. Function GetFromField(F : TField; ADefault : Integer) : Integer; overload;
  39. Function GetFromField(F : TField; const ADefault : String) : String; overload;
  40. Function GetFromField(F : TField; ADefault : Boolean) : Boolean; overload;
  41. Function GetFromDateTimeField(F : TField; ADefault : TDateTime) : TDateTime; overload;
  42. Function GetFromField(F : TField; ADefault : Double) : Double; overload;
  43. Function GetFromField(F : TField; ADefault : Single) : Single; overload;
  44. Function GetFromField(F : TField; ADefault : Int64) : Int64; overload;
  45. Function GetFromField(F : TField; ADefault : LongWord) : LongWord; overload;
  46. Function GetFromField(F : TField; ADefault : Currency) : Currency; overload;
  47. Function GetFromField(F : TField; const ADefault : UnicodeString) : UnicodeString; overload;
  48. Function GetFromField(F : TField; const ADefault : WideString) : WideString; overload;
  49. Function GetFromField(F : TField; ADefault : TBytes) : TBytes; overload;
  50. Property Dataset : TDataset Read FDataset;
  51. Property FreeDataset : Boolean Read FFreeDataset Write FFreeDataset;
  52. end;
  53. TFieldMapClass = Class of TFieldMap;
  54. { TParamMap }
  55. TParamMap = Class(TObject)
  56. private
  57. FParams: TParams;
  58. Protected
  59. Function FindParam(const FN : String) : TParam;
  60. Function ParamByName(const FN : String) : TParam;
  61. Public
  62. Constructor Create(AParams : TParams);
  63. Procedure InitParams; virtual; abstract;
  64. Procedure SaveObject(AObject : TObject); virtual; abstract;
  65. Property Params : TParams Read FParams;
  66. end;
  67. { $INTERFACES CORBA}
  68. ITypeSafeDatasetAccess = Interface ['{67496051-66AA-474E-9CB2-A4AEAA7A2324}']
  69. // Property getter/setter
  70. procedure SetFreeDataset(AValue: Boolean);
  71. function GetFreeDataset: Boolean;
  72. function GetActive: boolean;
  73. function GetIsEmpty: boolean;
  74. function GetModified: Boolean;
  75. function GetRecNo: integer;
  76. function GetRecordCount: integer;
  77. function GetState: TDatasetState;
  78. function GetBOF: Boolean;
  79. function GetDataset: TDataset;
  80. function GetEOF: Boolean;
  81. procedure SetActive(AValue: boolean);
  82. procedure SetRecNo(AValue: integer);
  83. // Examine data
  84. function IsFieldNull(const FieldName : String) : boolean;
  85. function IsFieldNull(const FieldIndex : Integer) : boolean;
  86. // Open/close
  87. procedure Open;
  88. procedure Close;
  89. // Navigation
  90. procedure First;
  91. procedure Prior;
  92. Procedure Next;
  93. procedure Last;
  94. function Locate(const aKeyFields: string; const aKeyValues: Variant; aOptions: TLocateOptions = []): Boolean;
  95. function Lookup(const aKeyFields: string; const aKeyValues: Variant; const aResultFields: string): Variant;
  96. // Modification
  97. Procedure Append;
  98. Procedure Insert;
  99. Procedure Edit;
  100. Procedure Post;
  101. Procedure Delete;
  102. Procedure Cancel;
  103. Procedure ApplyUpdates;
  104. procedure ClearField(const FieldName : String);
  105. procedure ClearField(const FieldIndex : Integer);
  106. // Properties
  107. Property EOF : Boolean Read GetEOF;
  108. Property BOF : Boolean Read GetBOF;
  109. Property Dataset : TDataset Read GetDataset;
  110. property IsEmpty : boolean read GetIsEmpty;
  111. property State : TDatasetState read GetState;
  112. property RecordCount: integer read GetRecordCount;
  113. property RecNo : integer read GetRecNo write SetRecNo;
  114. property Active: boolean read GetActive write SetActive;
  115. Property Modified : Boolean Read GetModified;
  116. Property FreeDataset : Boolean Read GetFreeDataset Write SetFreeDataset;
  117. end;
  118. { TTypeSafeDatasetAccess }
  119. TTypeSafeDatasetAccess = Class(TInterfacedObject, ITypeSafeDatasetAccess)
  120. private
  121. FFieldMap: TFieldMap;
  122. function GetActive: boolean;
  123. function GetIsEmpty: boolean;
  124. function GetModified: Boolean;
  125. function GetFreeDataset: Boolean;
  126. function GetRecNo: integer;
  127. function GetRecordCount: integer;
  128. function GetState: TDatasetState;
  129. procedure SetActive(AValue: boolean);
  130. procedure SetFreeDataset(AValue: Boolean);
  131. procedure SetRecNo(AValue: integer);
  132. Protected
  133. Class Function FieldMapClass : TFieldMapClass; virtual; abstract;
  134. function GetBOF: Boolean;
  135. function GetDataset: TDataset;
  136. function GetEOF: Boolean;
  137. Property FieldMap : TFieldMap Read FFieldMap;
  138. Public
  139. Constructor Create(aDataset : TDataset; HookOnOpen : Boolean = True);
  140. Destructor Destroy; override;
  141. function IsFieldNull(const FieldName : String) : boolean;
  142. function IsFieldNull(const FieldIndex : Integer) : boolean;
  143. procedure ClearField(const FieldName : String);
  144. procedure ClearField(const FieldIndex : Integer);
  145. // Open/close
  146. procedure Open;
  147. procedure Close;
  148. // Navigation
  149. procedure First;
  150. procedure Prior;
  151. Procedure Next;
  152. procedure Last;
  153. function Locate(const aKeyFields: string; const aKeyValues: Variant; aOptions: TLocateOptions = []): Boolean;
  154. function Lookup(const aKeyFields: string; const aKeyValues: Variant;
  155. const aResultFields: string): Variant;
  156. // Modification
  157. Procedure Append;
  158. Procedure Insert;
  159. Procedure Edit;
  160. Procedure Post;
  161. Procedure Delete;
  162. Procedure Cancel;
  163. Procedure ApplyUpdates; virtual;
  164. Property EOF : Boolean Read GetEOF;
  165. Property BOF : Boolean Read GetBOF;
  166. Property Dataset : TDataset Read GetDataset;
  167. property IsEmpty : boolean read GetIsEmpty;
  168. property State : TDatasetState read GetState;
  169. property RecordCount: integer read GetRecordCount;
  170. property RecNo : integer read GetRecNo write SetRecNo;
  171. property Active: boolean read GetActive write SetActive;
  172. Property Modified : Boolean Read GetModified;
  173. Property FreeDataset : Boolean Read GetFreeDataset Write SetFreeDataset;
  174. end;
  175. { TBlobProxyStream }
  176. TBlobProxyStream = Class(TOwnerStream)
  177. Private
  178. FChangeCount : Integer;
  179. FOnChange: TNotifyEvent;
  180. function GetUpdating: Boolean;
  181. Protected
  182. Procedure DoChanged; virtual;
  183. Procedure BeginUpdate; virtual;
  184. Procedure EndUpdate; virtual;
  185. function GetSize: Int64; override;
  186. procedure SetSize(const aValue: Int64); override;
  187. function GetPosition: Int64; override;
  188. procedure SetPosition(const aValue: Int64); override;
  189. Public
  190. Constructor create; overload;
  191. function Read(var Buffer; Count: Longint): Longint; override;
  192. function Write(const Buffer; Count: Longint): Longint; override;
  193. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; overload;
  194. property OnChange: TNotifyEvent read FOnChange write FOnChange;
  195. Property Updating : Boolean Read GetUpdating;
  196. end;
  197. implementation
  198. resourcestring
  199. SErrNoDataset = '%s: No dataset available.';
  200. SErrNoParamsForParam = '%s: No params to search param "%s".';
  201. SErrNoObjectToLoad = '%s: No object to load';
  202. function TBlobProxyStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  203. begin
  204. Result := Source.Seek(Offset, Origin);
  205. end;
  206. procedure TBlobProxyStream.SetPosition(const aValue: Int64);
  207. begin
  208. Source.Position := aValue;
  209. end;
  210. procedure TBlobProxyStream.SetSize(const aValue: Int64);
  211. begin
  212. Source.Size := aValue;
  213. DoChanged;
  214. end;
  215. function TBlobProxyStream.Write(const Buffer; Count: Longint): Longint;
  216. begin
  217. Result := Source.Write(Buffer, Count);
  218. DoChanged;
  219. end;
  220. procedure TBlobProxyStream.BeginUpdate;
  221. begin
  222. inc(FChangeCount);
  223. end;
  224. constructor TBlobProxyStream.create;
  225. begin
  226. Inherited Create(TMemoryStream.Create);
  227. SourceOwner:=True;
  228. end;
  229. procedure TBlobProxyStream.EndUpdate;
  230. begin
  231. if FChangeCount > 0 then
  232. Dec(FChangeCount);
  233. DoChanged;
  234. end;
  235. function TBlobProxyStream.GetPosition: Int64;
  236. begin
  237. Result := Source.Position;
  238. end;
  239. function TBlobProxyStream.GetSize: Int64;
  240. begin
  241. Result := Source.Size;
  242. end;
  243. function TBlobProxyStream.GetUpdating: Boolean;
  244. begin
  245. Result:=FChangeCount>0;
  246. end;
  247. procedure TBlobProxyStream.DoChanged;
  248. begin
  249. if (FChangeCount = 0) and Assigned(OnChange) then
  250. OnChange(Self);
  251. end;
  252. function TBlobProxyStream.Read(var Buffer; Count: Longint): Longint;
  253. begin
  254. Result := Source.Read(Buffer, Count);
  255. end;
  256. { TTypeSafeDatasetAccess }
  257. function TTypeSafeDatasetAccess.GetIsEmpty: boolean;
  258. begin
  259. With Dataset do
  260. Result:=EOF and BOF;
  261. end;
  262. function TTypeSafeDatasetAccess.GetModified: Boolean;
  263. begin
  264. Result:=Dataset.Modified;
  265. end;
  266. function TTypeSafeDatasetAccess.GetFreeDataset: Boolean;
  267. begin
  268. Result:=FFieldMap.FreeDataset;
  269. end;
  270. function TTypeSafeDatasetAccess.GetActive: boolean;
  271. begin
  272. Result:=Dataset.Active;
  273. end;
  274. function TTypeSafeDatasetAccess.GetRecNo: integer;
  275. begin
  276. Result:=Dataset.RecNo;
  277. end;
  278. function TTypeSafeDatasetAccess.GetRecordCount: integer;
  279. begin
  280. Result:=Dataset.RecordCount
  281. end;
  282. function TTypeSafeDatasetAccess.GetState: TDatasetState;
  283. begin
  284. Result:=Dataset.State;
  285. end;
  286. procedure TTypeSafeDatasetAccess.SetActive(AValue: boolean);
  287. begin
  288. Dataset.Active:=AValue;
  289. end;
  290. procedure TTypeSafeDatasetAccess.SetFreeDataset(AValue: Boolean);
  291. begin
  292. FFieldMap.FreeDataset:=AValue;
  293. end;
  294. procedure TTypeSafeDatasetAccess.SetRecNo(AValue: integer);
  295. begin
  296. Dataset.RecNo:=AValue;
  297. end;
  298. function TTypeSafeDatasetAccess.GetBOF: Boolean;
  299. begin
  300. Result:=Dataset.BOF;
  301. end;
  302. function TTypeSafeDatasetAccess.GetDataset: TDataset;
  303. begin
  304. Result:=FieldMap.Dataset;
  305. end;
  306. function TTypeSafeDatasetAccess.GetEOF: Boolean;
  307. begin
  308. Result:=Dataset.EOF;
  309. end;
  310. procedure TTypeSafeDatasetAccess.ApplyUpdates;
  311. begin
  312. // Needs to be implemented by descendents
  313. end;
  314. constructor TTypeSafeDatasetAccess.Create(aDataset: TDataset; HookOnOpen : Boolean = True);
  315. begin
  316. FFieldMap:=FieldMapClass.Create(aDataset,HookOnOpen);
  317. end;
  318. destructor TTypeSafeDatasetAccess.Destroy;
  319. begin
  320. FreeAndNil(FFieldMap);
  321. inherited Destroy;
  322. end;
  323. function TTypeSafeDatasetAccess.IsFieldNull(const FieldName: String): boolean;
  324. begin
  325. Result:=Dataset.FieldByName(FieldName).IsNull;
  326. end;
  327. function TTypeSafeDatasetAccess.IsFieldNull(const FieldIndex: Integer): boolean;
  328. begin
  329. Result:=Dataset.Fields[FieldIndex].IsNull;
  330. end;
  331. procedure TTypeSafeDatasetAccess.ClearField(const FieldName: String);
  332. begin
  333. Dataset.FieldByName(FieldName).Clear;
  334. end;
  335. procedure TTypeSafeDatasetAccess.ClearField(const FieldIndex: Integer);
  336. begin
  337. Dataset.Fields[FieldIndex].Clear;
  338. end;
  339. procedure TTypeSafeDatasetAccess.Open;
  340. begin
  341. Dataset.Open;
  342. end;
  343. procedure TTypeSafeDatasetAccess.Close;
  344. begin
  345. Dataset.Close;
  346. end;
  347. procedure TTypeSafeDatasetAccess.First;
  348. begin
  349. Dataset.First;
  350. end;
  351. procedure TTypeSafeDatasetAccess.Append;
  352. begin
  353. Dataset.Append;
  354. end;
  355. procedure TTypeSafeDatasetAccess.Insert;
  356. begin
  357. Dataset.Insert;
  358. end;
  359. procedure TTypeSafeDatasetAccess.Edit;
  360. begin
  361. Dataset.Edit;
  362. end;
  363. procedure TTypeSafeDatasetAccess.Next;
  364. begin
  365. Dataset.Next;
  366. end;
  367. procedure TTypeSafeDatasetAccess.Last;
  368. begin
  369. Dataset.Last;
  370. end;
  371. function TTypeSafeDatasetAccess.Locate(const aKeyFields: string;
  372. const aKeyValues: Variant; aOptions: TLocateOptions): Boolean;
  373. begin
  374. Result:=Dataset.Locate(aKeyFields,AKeyValues,aOptions);
  375. end;
  376. function TTypeSafeDatasetAccess.Lookup(const aKeyFields: string;
  377. const aKeyValues: Variant; const aResultFields: string): Variant;
  378. begin
  379. Result:=Dataset.Lookup(aKeyFields,aKeyValues,aResultFields);
  380. end;
  381. procedure TTypeSafeDatasetAccess.Prior;
  382. begin
  383. Dataset.Prior;
  384. end;
  385. procedure TTypeSafeDatasetAccess.Post;
  386. begin
  387. Dataset.Post;
  388. end;
  389. procedure TTypeSafeDatasetAccess.Delete;
  390. begin
  391. Dataset.Delete;
  392. end;
  393. procedure TTypeSafeDatasetAccess.Cancel;
  394. begin
  395. Dataset.Cancel;
  396. end;
  397. { TParamMap }
  398. function TParamMap.FindParam(const FN: String): TParam;
  399. begin
  400. Result:=FParams.FindParam(FN);
  401. {if (Result=Nil) then
  402. Writeln(ClassName,' param ',FN,' not found');}
  403. end;
  404. function TParamMap.ParamByName(const FN: String): TParam;
  405. begin
  406. If (FParams=Nil) then
  407. Raise Exception.CreateFmt(SErrNoParamsForParam,[ClassName,FN]);
  408. Result:=FParams.ParamByName(FN);
  409. end;
  410. constructor TParamMap.Create(AParams: TParams);
  411. begin
  412. FParams:=AParams;
  413. InitParams;
  414. end;
  415. { TFieldMap }
  416. constructor TFieldMap.Create(ADataset: TDataset; HookOnOpen : Boolean = False);
  417. begin
  418. if (ADataset=Nil) then
  419. Raise EFieldMap.CreateFmt(SErrNoDataset,[ClassName]);
  420. FDataset:=ADataset;
  421. if HookOnOpen then
  422. begin
  423. FOldOnOpen:=FDataset.AfterOpen;
  424. FDataset.AfterOpen:=@DoOnOpen;
  425. end;
  426. if FDataset.Active then
  427. InitFields;
  428. end;
  429. destructor TFieldMap.Destroy;
  430. begin
  431. if FFreeDataset then
  432. FreeAndNil(FFreeDataset);
  433. inherited Destroy;
  434. end;
  435. procedure TFieldMap.LoadObject(AObject: TObject);
  436. begin
  437. If (AObject=Nil) then
  438. Raise EFieldMap.CreateFmt(SErrNoObjectToLoad,[ClassName]);
  439. end;
  440. function TFieldMap.GetFromField(F: TField; ADefault: TBCD): TBCD;
  441. begin
  442. If Assigned(F) then
  443. Result:=F.AsBCD
  444. else
  445. Result:=ADefault;
  446. end;
  447. function TFieldMap.FieldByName(const FN: String): TField;
  448. begin
  449. Result:=FDataset.FieldByName(FN)
  450. end;
  451. procedure TFieldMap.DoOnOpen(Sender: TDataset);
  452. begin
  453. InitFields;
  454. If Assigned(FOldOnOpen) then
  455. FOldOnOpen(Sender);
  456. end;
  457. function TFieldMap.FindField(const FN: String): TField;
  458. begin
  459. If (FDataset=Nil) then
  460. Result:=Nil
  461. else
  462. Result:=FDataset.FindField(FN);
  463. end;
  464. function TFieldMap.GetFromField(F: TField; ADefault: Integer): Integer;
  465. begin
  466. If Assigned(F) then
  467. Result:=F.AsInteger
  468. else
  469. Result:=ADefault;
  470. end;
  471. function TFieldMap.GetFromField(F: TField; const ADefault: String): String;
  472. begin
  473. If Assigned(F) then
  474. Result:=F.AsString
  475. else
  476. Result:=ADefault;
  477. end;
  478. function TFieldMap.GetFromField(F: TField; ADefault: Boolean): Boolean;
  479. begin
  480. If Assigned(F) then
  481. begin
  482. if (F is TStringField) then
  483. Result:=(F.AsString='+')
  484. else
  485. Result:=F.AsBoolean
  486. end
  487. else
  488. Result:=ADefault;
  489. end;
  490. function TFieldMap.GetFromDateTimeField(F: TField; ADefault: TDateTime): TDateTime;
  491. begin
  492. If Assigned(F) then
  493. Result:=F.AsDateTime
  494. else
  495. Result:=ADefault;
  496. end;
  497. function TFieldMap.GetFromField(F: TField; ADefault: Double): Double;
  498. begin
  499. If Assigned(F) then
  500. if F.DataType in [ftDate,ftDateTime,ftTime,ftTimeStamp] then
  501. Result:=F.AsDateTime
  502. else
  503. Result:=F.AsFloat
  504. else
  505. Result:=ADefault;
  506. end;
  507. function TFieldMap.GetFromField(F: TField; ADefault: Single): Single;
  508. begin
  509. If Assigned(F) then
  510. Result:=F.AsSingle
  511. else
  512. Result:=ADefault;
  513. end;
  514. function TFieldMap.GetFromField(F: TField; ADefault: Int64): Int64;
  515. begin
  516. If Assigned(F) then
  517. Result:=F.AsLargeInt
  518. else
  519. Result:=ADefault;
  520. end;
  521. function TFieldMap.GetFromField(F: TField; ADefault: LongWord): LongWord;
  522. begin
  523. If Assigned(F) then
  524. Result:=F.AsLongWord
  525. else
  526. Result:=ADefault;
  527. end;
  528. function TFieldMap.GetFromField(F: TField; ADefault: Currency): Currency;
  529. begin
  530. If Assigned(F) then
  531. Result:=F.AsCurrency
  532. else
  533. Result:=ADefault;
  534. end;
  535. function TFieldMap.GetFromField(F: TField; const ADefault: UnicodeString): UnicodeString;
  536. begin
  537. If Assigned(F) then
  538. Result:=F.AsUnicodeString
  539. else
  540. Result:=ADefault;
  541. end;
  542. function TFieldMap.GetFromField(F: TField; const ADefault: WideString): WideString;
  543. begin
  544. If Assigned(F) then
  545. Result:=F.AsWideString
  546. else
  547. Result:=ADefault;
  548. end;
  549. function TFieldMap.GetFromField(F: TField; ADefault: TBytes): TBytes;
  550. begin
  551. If Assigned(F) then
  552. Result:=F.AsBytes
  553. else
  554. Result:=ADefault;
  555. end;
  556. end.