View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0038344 | pas2js | rtl | public | 2021-01-11 12:28 | 2021-01-23 11:32 |
Reporter | henrique | Assigned To | Michael Van Canneyt | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | resolved | Resolution | fixed | ||
Platform | Pas2Js | OS | Windows | ||
Fixed in Version | trunk | ||||
Summary | 0038344: TDataSet field implementation | ||||
Description | I started the implementation of TDataSetField. | ||||
Tags | No tags attached. | ||||
Fixed in Revision | 1068 | ||||
Attached Files |
|
|
0001-Implementa-o-inicial-do-DataSetField.patch (7,543 bytes)
From f4d5025c95f88df69c8a2d19d7b3f822a19ee28c Mon Sep 17 00:00:00 2001 From: Henrique Gottardi Werlang <henriquewerlang@hotmail.com> Date: Fri, 8 Jan 2021 10:58:45 -0300 Subject: [PATCH] =?UTF-8?q?Implementa=C3=A7=C3=A3o=20inicial=20do=20DataSe?= =?UTF-8?q?tField.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/fcl-db/db.pas | 105 +++++++++++++++++++++++++++++++++--- packages/fcl-db/dbconst.pas | 2 + 2 files changed, 101 insertions(+), 6 deletions(-) diff --git a/packages/fcl-db/db.pas b/packages/fcl-db/db.pas index 56fa3fa..e7ddc03 100644 --- a/packages/fcl-db/db.pas +++ b/packages/fcl-db/db.pas @@ -20,10 +20,9 @@ unit DB; { $define dsdebug} interface -uses Classes, SysUtils, JS, Types, DateUtils; +uses Generics.Collections, Classes, SysUtils, JS, Types, DateUtils; const - dsMaxBufferCount = MAXINT div 8; dsMaxStringSize = 8192; @@ -34,7 +33,6 @@ const SQLDelimiterCharacters = [';',',',' ','(',')',#13,#10,#9]; type - { Misc Dataset types } TDataSetState = (dsInactive, dsBrowse, dsEdit, dsInsert, dsSetKey, @@ -729,6 +727,17 @@ type constructor Create(AOwner: TComponent); override; end; + TDataSetField = class(TField) + private + FNestedDataSet: TDataSet; + + procedure AssignNestedDataSet(Value: TDataSet); + protected + procedure Bind(Binding: Boolean); override; + public + constructor Create(AOwner: TComponent); override; + end; + { TIndexDef } TIndexDefs = class; @@ -1054,6 +1063,8 @@ type TOnRecordResolveEvent = Procedure (Sender : TDataset; info : TResolveInfo) of object; TApplyUpdatesEvent = Procedure (Sender : TDataset; info : TResolveResults) of object; + TNestedDataSetsList = specialize TList<TDataSet>; + {------------------------------------------------------------------------------} TDataSet = class(TComponent) @@ -1127,6 +1138,9 @@ type FInApplyupdates : Boolean; FLoadCount : Integer; FMinLoadID : Integer; + FDataSetField: TDataSetField; + FNestedDataSets: TNestedDataSetsList; + FNestedDataSetClass: TDataSetClass; Procedure DoInsertAppend(DoAppend : Boolean); Procedure DoInternalOpen; Function GetBuffer (Index : longint) : TDataRecord; @@ -1146,6 +1160,7 @@ type // Callback for Tdataproxy.DoGetData; function ResolveRecordUpdate(anUpdate: TRecordUpdateDescriptor): Boolean; procedure HandleRequestResponse(ARequest: TDataRequest); + function GetNestedDataSets: TNestedDataSetsList; protected // Proxy methods // Override this to integrate package in local data @@ -1283,6 +1298,7 @@ type procedure SetBookmarkData(Var Buffer{%H-}: TDataRecord; Data{%H-}: TBookmark); virtual; procedure SetUniDirectional(const Value: Boolean); procedure Notification(AComponent: TComponent; Operation: TOperation); override; + procedure SetDataSetField(const Value: TDataSetField); virtual; // These use the active buffer function GetFieldData(Field: TField): JSValue; virtual; overload; procedure SetFieldData(Field: TField; AValue : JSValue); virtual; overload; @@ -1290,6 +1306,7 @@ type procedure SetFieldData(Field: TField; var Buffer: TDatarecord; AValue : JSValue); virtual; overload; class function FieldDefsClass : TFieldDefsClass; virtual; class function FieldsClass : TFieldsClass; virtual; + property NestedDataSets: TNestedDataSetsList read GetNestedDataSets; protected { abstract methods } function GetRecord(var Buffer: TDataRecord; GetMode: TGetMode; DoCheck: Boolean): TGetResult; virtual; abstract; procedure InternalClose; virtual; abstract; @@ -1360,6 +1377,7 @@ type procedure UpdateCursorPos; procedure UpdateRecord; Function GetPendingUpdates : TResolveInfoArray; + property DataSetField: TDataSetField read FDataSetField write SetDataSetField; Property Loading : Boolean Read GetIsLoading; property BlockReadSize: Integer read FBlockReadSize write SetBlockReadSize; property BOF: Boolean read FBOF; @@ -2343,10 +2361,9 @@ begin FIsUniDirectional := False; FAutoCalcFields := True; FDataRequestID:=0; + FNestedDataSetClass := TDataSetClass(Self.ClassType); end; - - destructor TDataSet.Destroy; var @@ -2356,6 +2373,7 @@ begin Active:=False; FFieldDefs.Free; FFieldList.Free; + FNestedDataSets.Free; With FDataSources do begin While Count>0 do @@ -2544,9 +2562,16 @@ procedure TDataSet.DataEvent(Event: TDataEvent; Info: JSValue); end; procedure HandleScrollOrChange; + var + NestedDataSet: TDataSet; begin if State <> dsInsert then UpdateCursorPos; + + if Assigned(FNestedDataSets) then + for NestedDataSet in FNestedDataSets do + if NestedDataSet.Active then + NestedDataSet.DataEvent(deParentScroll, 0); end; var @@ -3157,6 +3182,35 @@ begin // empty stub end; +procedure TDataSet.SetDataSetField(const Value: TDataSetField); +begin + if Value <> FDataSetField then + begin + if (Value <> nil) and ((Value.DataSet = Self) or + ((Value.DataSet.GetDataSource <> nil) and + (Value.DataSet.GetDataSource.DataSet = Self))) then + DatabaseError(SCircularDataLink, Self); + if Assigned(Value) and not InheritsFrom(Value.DataSet.FNestedDataSetClass) then + DatabaseErrorFmt(SNestedDataSetClass, [Value.DataSet.FNestedDataSetClass.ClassName], Self); + if Active then Close; + if Assigned(FDataSetField) then + FDataSetField.AssignNestedDataSet(nil); + FDataSetField := Value; + if Assigned(Value) then + begin + Value.AssignNestedDataSet(Self); + if Value.DataSet.Active then Open; + end; + end; +end; + +function TDataSet.GetNestedDataSets: TNestedDataSetsList; +begin + if not Assigned(FNestedDataSets) then + FNestedDataSets := TNestedDataSetsList.Create; + + Result := FNestedDataSets; +end; function TDataSet.GetFieldData(Field: TField; Buffer: TDatarecord): JSValue; @@ -9001,6 +9055,45 @@ begin end; end; -initialization +{ TDataSetField } + +constructor TDataSetField.Create(AOwner: TComponent); +begin + inherited; + + SetDataType(ftDataSet); +end; + +procedure TDataSetField.Bind(Binding: Boolean); +begin + inherited; + if Assigned(FNestedDataSet) then + if Binding then + begin + if FNestedDataSet.State = dsInActive then + FNestedDataSet.Open; + end + else + FNestedDataSet.Close; +end; + +procedure TDataSetField.AssignNestedDataSet(Value: TDataSet); +begin + if Assigned(FNestedDataSet) then + begin + FNestedDataSet.Close; + FNestedDataSet.FDataSetField := nil; + if Assigned(DataSet) then + DataSet.NestedDataSets.Remove(FNestedDataSet); + end; + if Assigned(Value) then + begin + DataSet.NestedDataSets.Add(Value); + FFields := Value.Fields; + end + else + FFields := nil; + FNestedDataSet := Value; +end; end. diff --git a/packages/fcl-db/dbconst.pas b/packages/fcl-db/dbconst.pas index 19443ad..3e8f02d 100644 --- a/packages/fcl-db/dbconst.pas +++ b/packages/fcl-db/dbconst.pas @@ -128,6 +128,8 @@ Resourcestring SatEOFInternalOnly = 'loAtEOF is for internal use only.'; SErrInsertingSameRecordtwice = 'Attempt to insert the same record twice.'; SErrDoApplyUpdatesNeedsProxy = 'Cannot apply updates without Data proxy'; + SNestedDataSetClass = 'Nested dataset must inherit from %s'; + SCircularDataLink = 'Circular datalinks are not allowed'; Implementation -- 2.29.2.windows.2 |
|
Remove the dependency on generics please. No generics in DB units. |
|
OK. But may I know why? |
|
3 reasons: 1. It creates an extra dependency. Less units is better. 2. Every generic specialization adds code to the binary. I am not OK with that unless there is a good reason. 3. TDataset stems from a time when generics were not available and is programmed a certain way. I don't think units that predate generics must now be populated with generic concepts. Maybe one day the whole DB unit can be reprogrammed with generics; but I don't think the 2 concepts should be mixed. |
|
Okey! Attached the implementation without the generics reference. 0001-Implementa-o-inicial-do-DataSetField-2.patch (7,530 bytes)
From 8d4adba303f78fe202e2078634a11eccf8dd77c6 Mon Sep 17 00:00:00 2001 From: Henrique Gottardi Werlang <henriquewerlang@hotmail.com> Date: Fri, 15 Jan 2021 08:48:47 -0300 Subject: [PATCH] =?UTF-8?q?Implementa=C3=A7=C3=A3o=20inicial=20do=20DataSe?= =?UTF-8?q?tField.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/fcl-db/db.pas | 110 ++++++++++++++++++++++++++++++++++-- packages/fcl-db/dbconst.pas | 2 + 2 files changed, 107 insertions(+), 5 deletions(-) diff --git a/packages/fcl-db/db.pas b/packages/fcl-db/db.pas index 56fa3fa..8ef67cf 100644 --- a/packages/fcl-db/db.pas +++ b/packages/fcl-db/db.pas @@ -23,7 +23,6 @@ interface uses Classes, SysUtils, JS, Types, DateUtils; const - dsMaxBufferCount = MAXINT div 8; dsMaxStringSize = 8192; @@ -34,7 +33,6 @@ const SQLDelimiterCharacters = [';',',',' ','(',')',#13,#10,#9]; type - { Misc Dataset types } TDataSetState = (dsInactive, dsBrowse, dsEdit, dsInsert, dsSetKey, @@ -729,6 +727,17 @@ type constructor Create(AOwner: TComponent); override; end; + TDataSetField = class(TField) + private + FNestedDataSet: TDataSet; + + procedure AssignNestedDataSet(Value: TDataSet); + protected + procedure Bind(Binding: Boolean); override; + public + constructor Create(AOwner: TComponent); override; + end; + { TIndexDef } TIndexDefs = class; @@ -1054,6 +1063,8 @@ type TOnRecordResolveEvent = Procedure (Sender : TDataset; info : TResolveInfo) of object; TApplyUpdatesEvent = Procedure (Sender : TDataset; info : TResolveResults) of object; + TNestedDataSetsList = TFPList; + {------------------------------------------------------------------------------} TDataSet = class(TComponent) @@ -1127,6 +1138,9 @@ type FInApplyupdates : Boolean; FLoadCount : Integer; FMinLoadID : Integer; + FDataSetField: TDataSetField; + FNestedDataSets: TNestedDataSetsList; + FNestedDataSetClass: TDataSetClass; Procedure DoInsertAppend(DoAppend : Boolean); Procedure DoInternalOpen; Function GetBuffer (Index : longint) : TDataRecord; @@ -1146,6 +1160,7 @@ type // Callback for Tdataproxy.DoGetData; function ResolveRecordUpdate(anUpdate: TRecordUpdateDescriptor): Boolean; procedure HandleRequestResponse(ARequest: TDataRequest); + function GetNestedDataSets: TNestedDataSetsList; protected // Proxy methods // Override this to integrate package in local data @@ -1283,6 +1298,7 @@ type procedure SetBookmarkData(Var Buffer{%H-}: TDataRecord; Data{%H-}: TBookmark); virtual; procedure SetUniDirectional(const Value: Boolean); procedure Notification(AComponent: TComponent; Operation: TOperation); override; + procedure SetDataSetField(const Value: TDataSetField); virtual; // These use the active buffer function GetFieldData(Field: TField): JSValue; virtual; overload; procedure SetFieldData(Field: TField; AValue : JSValue); virtual; overload; @@ -1290,6 +1306,7 @@ type procedure SetFieldData(Field: TField; var Buffer: TDatarecord; AValue : JSValue); virtual; overload; class function FieldDefsClass : TFieldDefsClass; virtual; class function FieldsClass : TFieldsClass; virtual; + property NestedDataSets: TNestedDataSetsList read GetNestedDataSets; protected { abstract methods } function GetRecord(var Buffer: TDataRecord; GetMode: TGetMode; DoCheck: Boolean): TGetResult; virtual; abstract; procedure InternalClose; virtual; abstract; @@ -1360,6 +1377,7 @@ type procedure UpdateCursorPos; procedure UpdateRecord; Function GetPendingUpdates : TResolveInfoArray; + property DataSetField: TDataSetField read FDataSetField write SetDataSetField; Property Loading : Boolean Read GetIsLoading; property BlockReadSize: Integer read FBlockReadSize write SetBlockReadSize; property BOF: Boolean read FBOF; @@ -2343,10 +2361,9 @@ begin FIsUniDirectional := False; FAutoCalcFields := True; FDataRequestID:=0; + FNestedDataSetClass := TDataSetClass(Self.ClassType); end; - - destructor TDataSet.Destroy; var @@ -2356,6 +2373,7 @@ begin Active:=False; FFieldDefs.Free; FFieldList.Free; + FNestedDataSets.Free; With FDataSources do begin While Count>0 do @@ -2544,9 +2562,23 @@ procedure TDataSet.DataEvent(Event: TDataEvent; Info: JSValue); end; procedure HandleScrollOrChange; + var + A: Integer; + + NestedDataSet: TDataSet; + begin if State <> dsInsert then UpdateCursorPos; + + if Assigned(FNestedDataSets) then + for A := 0 to Pred(NestedDataSets.Count) do + begin + NestedDataSet := TDataSet(NestedDataSets[A]); + + if NestedDataSet.Active then + NestedDataSet.DataEvent(deParentScroll, 0); + end; end; var @@ -3157,6 +3189,35 @@ begin // empty stub end; +procedure TDataSet.SetDataSetField(const Value: TDataSetField); +begin + if Value <> FDataSetField then + begin + if (Value <> nil) and ((Value.DataSet = Self) or + ((Value.DataSet.GetDataSource <> nil) and + (Value.DataSet.GetDataSource.DataSet = Self))) then + DatabaseError(SCircularDataLink, Self); + if Assigned(Value) and not InheritsFrom(Value.DataSet.FNestedDataSetClass) then + DatabaseErrorFmt(SNestedDataSetClass, [Value.DataSet.FNestedDataSetClass.ClassName], Self); + if Active then Close; + if Assigned(FDataSetField) then + FDataSetField.AssignNestedDataSet(nil); + FDataSetField := Value; + if Assigned(Value) then + begin + Value.AssignNestedDataSet(Self); + if Value.DataSet.Active then Open; + end; + end; +end; + +function TDataSet.GetNestedDataSets: TNestedDataSetsList; +begin + if not Assigned(FNestedDataSets) then + FNestedDataSets := TNestedDataSetsList.Create; + + Result := FNestedDataSets; +end; function TDataSet.GetFieldData(Field: TField; Buffer: TDatarecord): JSValue; @@ -9001,6 +9062,45 @@ begin end; end; -initialization +{ TDataSetField } + +constructor TDataSetField.Create(AOwner: TComponent); +begin + inherited; + + SetDataType(ftDataSet); +end; + +procedure TDataSetField.Bind(Binding: Boolean); +begin + inherited; + if Assigned(FNestedDataSet) then + if Binding then + begin + if FNestedDataSet.State = dsInActive then + FNestedDataSet.Open; + end + else + FNestedDataSet.Close; +end; + +procedure TDataSetField.AssignNestedDataSet(Value: TDataSet); +begin + if Assigned(FNestedDataSet) then + begin + FNestedDataSet.Close; + FNestedDataSet.FDataSetField := nil; + if Assigned(DataSet) then + DataSet.NestedDataSets.Remove(FNestedDataSet); + end; + if Assigned(Value) then + begin + DataSet.NestedDataSets.Add(Value); + FFields := Value.Fields; + end + else + FFields := nil; + FNestedDataSet := Value; +end; end. diff --git a/packages/fcl-db/dbconst.pas b/packages/fcl-db/dbconst.pas index 19443ad..3e8f02d 100644 --- a/packages/fcl-db/dbconst.pas +++ b/packages/fcl-db/dbconst.pas @@ -128,6 +128,8 @@ Resourcestring SatEOFInternalOnly = 'loAtEOF is for internal use only.'; SErrInsertingSameRecordtwice = 'Attempt to insert the same record twice.'; SErrDoApplyUpdatesNeedsProxy = 'Cannot apply updates without Data proxy'; + SNestedDataSetClass = 'Nested dataset must inherit from %s'; + SCircularDataLink = 'Circular datalinks are not allowed'; Implementation -- 2.30.0.windows.1 |
|
Applied with cosmetic changes, thank you very much ! |
Date Modified | Username | Field | Change |
---|---|---|---|
2021-01-11 12:28 | henrique | New Issue | |
2021-01-11 12:28 | henrique | File Added: 0001-Implementa-o-inicial-do-DataSetField.patch | |
2021-01-11 13:01 | Michael Van Canneyt | Note Added: 0128264 | |
2021-01-11 13:01 | Michael Van Canneyt | Assigned To | => Michael Van Canneyt |
2021-01-11 13:01 | Michael Van Canneyt | Status | new => assigned |
2021-01-14 12:51 | henrique | Note Added: 0128315 | |
2021-01-14 13:39 | Michael Van Canneyt | Note Added: 0128317 | |
2021-01-15 12:51 | henrique | Note Added: 0128341 | |
2021-01-15 12:51 | henrique | File Added: 0001-Implementa-o-inicial-do-DataSetField-2.patch | |
2021-01-23 11:32 | Michael Van Canneyt | Status | assigned => resolved |
2021-01-23 11:32 | Michael Van Canneyt | Resolution | open => fixed |
2021-01-23 11:32 | Michael Van Canneyt | Fixed in Version | => trunk |
2021-01-23 11:32 | Michael Van Canneyt | Fixed in Revision | => 1068 |
2021-01-23 11:32 | Michael Van Canneyt | Note Added: 0128508 | |
2021-01-23 11:32 | Michael Van Canneyt | Note Edited: 0128508 | View Revisions |