* Added filtering

This commit is contained in:
michael 2018-12-30 16:17:11 +00:00
parent 50d5a647bd
commit 5d7b0b4891

View File

@ -5,7 +5,7 @@ unit JSONDataset;
interface
uses
Types, JS, DB, Classes, SysUtils, typinfo;
Types, JS, DB, Classes, SysUtils, typinfo, fpexprpars;
type
TBaseJSONDataset = Class;
@ -255,14 +255,28 @@ type
// When editing, this object is edited.
FEditIdx : Integer;
FEditRow : JSValue;
// When filtering, this is the current row;
FFilterRow : JSValue;
FUseDateTimeFormatFields: Boolean;
FRowType: TJSONRowType;
FFilterExpression : TFPExpressionParser;
function GetFilterField(const AName: String): TFPExpressionResult;
procedure SetActiveIndex(AValue: String);
procedure SetIndexes(AValue: TJSONIndexDefs);
procedure SetMetaData(AValue: TJSObject);
procedure SetRows(AValue: TJSArray);
procedure SetRowType(AValue: TJSONRowType);
protected
// Determine filter value type based on field type
function FieldTypeToExpressionType(aDataType: TFieldType): TResultType; virtual;
// Callback for IsNull filter function.
function GetFilterIsNull(const Args: TExprParameterArray): TFPExpressionResult; virtual;
// Expression parser class. Override this to create a customized version.
function FilterExpressionClass: TFPExpressionParserClass; virtual;
// Create filter expression.
function CreateFilterExpression: TFPExpressionParser; virtual;
// Function called to check if current buffer should be accepted.
function DoFilterRecord: Boolean; virtual;
// Override this to return customized version.
function CreateIndexDefs: TJSONIndexDefs; virtual;
// override this to return a customized version if you are so inclined
@ -287,6 +301,8 @@ type
procedure InternalCancel; override;
procedure InternalInitFieldDefs; override;
procedure InternalSetToRecord(Buffer: TDataRecord); override;
procedure SetFilterText(const Value: string); override;
procedure SetFiltered(Value: Boolean); override;
function GetFieldClass(FieldType: TFieldType): TFieldClass; override;
function IsCursorOpen: Boolean; override;
// Bookmark operations
@ -1142,36 +1158,141 @@ begin
FCurrentIndex:=FDefaultIndex;
end;
function TBaseJSONDataSet.FilterExpressionClass : TFPExpressionParserClass;
begin
Result:=TFPExpressionParser;
end;
function TBaseJSONDataSet.GetFilterIsNull(Const Args : TExprParameterArray) : TFPExpressionResult;
begin
Result.ResultType:=rtBoolean;
Result.ResValue:=FieldByName(String(Args[0].resValue)).IsNull;
end;
function TBaseJSONDataSet.FieldTypeToExpressionType(aDataType : TFieldType) : TResultType;
begin
Case aDataType of
ftMemo,
ftFixedChar,
ftString : Result:=rtString;
ftInteger,
ftAutoInc,
ftLargeInt : Result:=rtInteger;
ftBoolean : Result:=rtBoolean;
ftFloat : Result:=rtFloat;
ftDate,
ftTime,
ftDateTime : Result:=rtDateTime;
else
DatabaseErrorFmt('Fields of type %s are not supported in filter expressions.',[Fieldtypenames[aDataType]],Self);
end;
end;
function TBaseJSONDataSet.GetFilterField(Const AName : String) : TFPExpressionResult;
Var
F : TField;
C : Currency;
begin
F:=FieldByName(aName);
Result.resultType:=FieldTypeToExpressionType(F.DataType);
case Result.resultType of
rtBoolean : Result.resValue:=F.AsBoolean;
rtInteger : Result.resValue:=F.AsLargeInt;
rtFloat : Result.resValue:=F.AsFloat;
rtDateTime : Result.resValue:=F.AsDateTime;
rtString : Result.resValue:=F.AsString;
rtCurrency :
begin
C:=Currency(F.AsFloat);
Result.resValue:=C;
end;
end;
// Writeln('Filtering field ',aName,'value: ',result.resValue);
end;
function TBaseJSONDataSet.CreateFilterExpression : TFPExpressionParser;
Var
I : Integer;
begin
Result:=FilterExpressionClass.Create(Self);
for I:=0 to Fields.Count-1 do
Result.Identifiers.AddVariable(Fields[i].FieldName,FieldTypeToExpressionType(Fields[i].DataType),@GetFilterField);
Result.Identifiers.AddFunction('IsNull','B','S',@GetFilterIsNull);
Result.Expression:=Filter;
end;
function TBaseJSONDataSet.DoFilterRecord : Boolean;
Var
DS : TDatasetState;
begin
// Writeln('Filtering');
Result:=True;
DS:=SetTempState(dsFilter);
try
if Assigned(OnFilterRecord) then
begin
OnFilterRecord(Self,Result);
if Not Result then
Exit;
end;
if not Filtered or (Filter='') then
Exit;
if (FFilterExpression=Nil) then
FFilterExpression:=CreateFilterExpression;
Result:=FFilterExpression.AsBoolean;
finally
RestoreState(DS);
end;
end;
function TBaseJSONDataSet.GetRecord(Var Buffer: TDataRecord; GetMode: TGetMode; DoCheck: Boolean): TGetResult;
Var
BkmIdx : Integer;
recordAccepted : Boolean;
begin
Result := grOK; // default
case GetMode of
gmNext: // move on
if fCurrent < fCurrentIndex.Count - 1 then
Inc (fCurrent)
else
Result := grEOF; // end of file
gmPrior: // move back
if fCurrent > 0 then
Dec (fCurrent)
else
Result := grBOF; // begin of file
gmCurrent: // check if empty
if fCurrent >= fCurrentIndex.Count then
Result := grEOF;
end;
if Result = grOK then // read the data
begin
BkmIdx:=FCurrentIndex.RecordIndex[FCurrent];
Buffer.Data:=FRows[bkmIdx];
Buffer.BookmarkFlag := bfCurrent;
Buffer.Bookmark:=BkmIdx;
CalculateFields(Buffer);
Repeat
recordAccepted:=True;
case GetMode of
gmNext: // move on
if fCurrent < fCurrentIndex.Count - 1 then
Inc (fCurrent)
else
Result := grEOF; // end of file
gmPrior: // move back
if fCurrent > 0 then
Dec (fCurrent)
else
Result := grBOF; // begin of file
gmCurrent: // check if empty
if fCurrent >= fCurrentIndex.Count then
Result := grEOF;
end;
if Result = grOK then // read the data
begin
BkmIdx:=FCurrentIndex.RecordIndex[FCurrent];
Buffer.Data:=FRows[bkmIdx];
Buffer.BookmarkFlag := bfCurrent;
Buffer.Bookmark:=BkmIdx;
CalculateFields(Buffer);
if Filtered then
begin
FFilterRow:=Buffer.Data;
recordAccepted:=DoFilterRecord;
end;
end;
until recordAccepted;
end;
function TBaseJSONDataSet.GetRecordCount: Integer;
@ -1355,6 +1476,22 @@ begin
FCurrent:=FCurrentIndex.FindRecord(Integer(Buffer.Bookmark));
end;
procedure TBaseJSONDataSet.SetFilterText(const Value: string);
begin
inherited SetFilterText(Value);
FreeAndNil(FFilterExpression);
if Active then
Resync([rmCenter]);
end;
procedure TBaseJSONDataSet.SetFiltered(Value: Boolean);
begin
inherited SetFiltered(Value);
FreeAndNil(FFilterExpression);
if Active then
Resync([rmCenter]);
end;
function TBaseJSONDataSet.GetFieldClass(FieldType: TFieldType): TFieldClass;
begin
If UseDateTimeFormatFields and (FieldType in [ftDate,ftDateTime,ftTime]) then
@ -1445,6 +1582,8 @@ var
begin
if State in [dsCalcFields,dsInternalCalc] then
R:=CalcBuffer.data
else if (State=dsFilter) then
R:=FFilterRow
else if (FEditIdx=Buffer.Bookmark) then
begin
if State=dsOldValue then
@ -1525,6 +1664,7 @@ end;
destructor TBaseJSONDataSet.Destroy;
begin
FreeAndNil(FFilterExpression);
FreeAndNil(FIndexes);
FEditIdx:=-1;
FreeData;