123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- {
- This file is part of the Free Pascal Run time library.
- Copyright (c) 2021 by Michael Van Canneyt ([email protected])
- This file contains a Mustache DB context, getting data from a dataset
- See the File COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit fpdbmustache;
- {$mode ObjFPC}{$H+}
- interface
- uses
- Classes, SysUtils, db, fpMustache;
- Type
- { TDatasetCollectionItem }
- TDatasetCollectionItem = Class(TCollectionItem)
- private
- FDataset: TDataSet;
- FSection: String;
- Public
- Property Dataset : TDataSet Read FDataset Write FDataset;
- Property SectionName : String Read FSection Write FSection;
- end;
- TDatasetCollection = Class(TCollection)
- private
- function GetDS(aIndex : Integer): TDatasetCollectionItem;
- Public
- Function IndexOfDataset(aDataset : TDataset) : Integer;
- Function IndexOfSection(aSection : String) : Integer;
- Property Datasets[aIndex : Integer] : TDatasetCollectionItem Read GetDS; default;
- end;
- { TMustacheDBContext }
- TMustacheDBContext = Class(TMustacheContext)
- Private
- Type
- TPair = Record
- atStart : Boolean;
- Value : TDataset;
- end;
- Private
- FStack : Array of TPair;
- FCount : Integer;
- FStaticValues: TStrings;
- FDatasets : TDatasetCollection;
- Function FindField(Const aName : TMustacheString) : TField;
- function GetDataset(aIndex : Integer): TDatasetCollectionItem;
- function GetDatasetCount: INteger;
- procedure SetStaticValues(AValue: TStrings);
- Public
- Constructor Create(aCallback : TGetTextValueEvent); override;
- Destructor destroy; override;
- Procedure Clear;
- Function MoveNextSectionItem(Const aName : TMustacheString) : Boolean; override;
- Function PushSection(Const aName : TMustacheString) : TMustacheSectionType; override;
- Procedure PopSection(Const aName : TMustacheString); override;
- Function GetTextValue(Const aName : TMustacheString) : TMustacheString; override;
- Procedure AddDataset(aDataset : TDataset; aSectionName : String = '');
- Procedure RemoveDataset(aDataset : TDataset);
- Property StaticValues : TStrings Read FStaticValues Write SetStaticValues;
- Property Datasets[aIndex : Integer] : TDatasetCollectionItem Read GetDataset;
- Property DatasetCount : INteger Read GetDatasetCount;
- end;
- implementation
- uses StrUtils;
- Resourcestring
- SErrPopSectionNoPush = 'PopSection %s without push';
- SErrDatasetNameEmpty = 'Dataset name and section cannot both be empty';
- SErrDatasetEmpty = 'Dataset is Nil';
- SErrDuplicateDataSetName = 'Duplicate dataset name: %s';
- { TMustacheDBContext }
- function TMustacheDBContext.FindField(const aName: TMustacheString): TField;
- Var
- aCount : Integer;
- begin
- Result:=Nil;
- aCount:=FCount-1;
- While (Result=Nil) and (aCount>=0) do
- begin
- Result:=FStack[aCount].Value.FieldByName(aName);
- Dec(aCount);
- end;
- end;
- function TMustacheDBContext.GetDataset(aIndex : Integer
- ): TDatasetCollectionItem;
- begin
- Result:=FDatasets[aIndex];
- end;
- function TMustacheDBContext.GetDatasetCount: INteger;
- begin
- Result:=FDatasets.Count;
- end;
- procedure TMustacheDBContext.SetStaticValues(AValue: TStrings);
- begin
- if FStaticValues=AValue then Exit;
- FStaticValues.Assign(AValue);
- end;
- constructor TMustacheDBContext.Create(aCallback: TGetTextValueEvent);
- begin
- inherited Create(aCallback);
- FDatasets:=TDatasetCollection.Create(TDatasetCollectionItem);
- FStaticValues:=TStringList.Create;
- SetLength(FStack,JSONListGrowCount);
- FCount:=0;
- end;
- destructor TMustacheDBContext.destroy;
- begin
- FreeAndNil(FStaticValues);
- FreeAndNil(FDatasets);
- inherited destroy;
- end;
- procedure TMustacheDBContext.Clear;
- begin
- FStaticValues.Clear;
- FDatasets.Clear;
- end;
- function TMustacheDBContext.MoveNextSectionItem(const aName: TMustacheString
- ): Boolean;
- begin
- if FStack[FCount-1].atStart then
- FStack[FCount-1].atStart:=False
- else
- FStack[FCount-1].Value.Next;
- Result:=Not FStack[FCount-1].Value.EOF;
- end;
- function TMustacheDBContext.PushSection(const aName: TMustacheString
- ): TMustacheSectionType;
- Var
- aDS : TDataset;
- Idx : Integer;
- begin
- Result:=mstNone;
- Idx:=FDatasets.IndexOfSection(aName);
- if Idx=-1 then
- Exit;
- aDS:=FDatasets[Idx].Dataset;
- if aDS.IsEmpty then
- exit;
- if FCount=Length(FStack) then
- SetLength(FStack,FCount+JSONListGrowCount);
- FStack[FCount].Value:=aDS;
- FStack[FCount].atStart:=True;
- Inc(FCount,1);
- Result:=mstList;
- end;
- procedure TMustacheDBContext.PopSection(const aName: TMustacheString);
- begin
- if FCount<1 then
- Raise EMustache.CreateFmt(SErrPopSectionNoPush,[aName]);
- Dec(FCount,1);
- end;
- function TMustacheDBContext.GetTextValue(const aName: TMustacheString
- ): TMustacheString;
- Var
- F : TField;
- idx : Integer;
- begin
- F:=Nil;
- if Pos('.',aName)=0 then
- F:=FindField(aName)
- else if WordCount(aName,['.'])=2 then
- begin
- Idx:=FDatasets.IndexOfSection(ExtractWord(1,aName,['.']));
- if (Idx<>-1) then
- F:=FDatasets[Idx].Dataset.FindField(ExtractWord(2,aName,['.']));
- end;
- If Assigned(F) then
- Result:=F.AsString
- else
- begin
- Idx:=FStaticValues.IndexOfName(aName);
- if Idx<>-1 then
- Result:=FStaticValues.ValueFromIndex[Idx]
- else
- Result:=Inherited GetTextValue(aName);
- end;
- end;
- procedure TMustacheDBContext.AddDataset(aDataset: TDataset; aSectionName: String);
- Var
- DCI : TDatasetCollectionItem;
- aName : String;
- begin
- aName:=aSectionName;
- if aName='' then
- aName:=aDataset.Name;
- if aName='' then
- raise EMustache.Create(SErrDatasetNameEmpty);
- if aDataset=Nil then
- raise EMustache.Create(SErrDatasetEmpty);
- if FDatasets.IndexOfSection(aName)<>-1 then
- raise EMustache.CreateFmt(SErrDuplicateDataSetName, [aName]);
- DCI:=FDatasets.Add as TDatasetCollectionItem;
- DCI.Dataset:=aDataset;
- DCI.SectionName:=aName;
- end;
- procedure TMustacheDBContext.RemoveDataset(aDataset: TDataset);
- Var
- Idx : Integer;
- begin
- Idx:=FDatasets.IndexOfDataset(aDataset);
- if Idx<>-1 then
- FDatasets.Delete(Idx);
- end;
- { TDatasetCollection }
- function TDatasetCollection.GetDS(aIndex : Integer): TDatasetCollectionItem;
- begin
- Result:=Items[aIndex] as TDatasetCollectionItem;
- end;
- function TDatasetCollection.IndexOfDataset(aDataset: TDataset): Integer;
- begin
- Result:=Count-1;
- While (Result>=0) and (GetDS(Result).Dataset<>ADataset) do
- Dec(Result);
- end;
- function TDatasetCollection.IndexOfSection(aSection: String): Integer;
- begin
- Result:=Count-1;
- While (Result>=0) and not SameText(GetDS(Result).SectionName,ASection) do
- Dec(Result);
- end;
- end.
|