mirror of
https://gitlab.com/freepascal.org/fpc/pas2js.git
synced 2025-08-25 06:19:13 +02:00
* Added filtering
This commit is contained in:
parent
50d5a647bd
commit
5d7b0b4891
@ -5,7 +5,7 @@ unit JSONDataset;
|
|||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
Types, JS, DB, Classes, SysUtils, typinfo;
|
Types, JS, DB, Classes, SysUtils, typinfo, fpexprpars;
|
||||||
|
|
||||||
type
|
type
|
||||||
TBaseJSONDataset = Class;
|
TBaseJSONDataset = Class;
|
||||||
@ -255,14 +255,28 @@ type
|
|||||||
// When editing, this object is edited.
|
// When editing, this object is edited.
|
||||||
FEditIdx : Integer;
|
FEditIdx : Integer;
|
||||||
FEditRow : JSValue;
|
FEditRow : JSValue;
|
||||||
|
// When filtering, this is the current row;
|
||||||
|
FFilterRow : JSValue;
|
||||||
FUseDateTimeFormatFields: Boolean;
|
FUseDateTimeFormatFields: Boolean;
|
||||||
FRowType: TJSONRowType;
|
FRowType: TJSONRowType;
|
||||||
|
FFilterExpression : TFPExpressionParser;
|
||||||
|
function GetFilterField(const AName: String): TFPExpressionResult;
|
||||||
procedure SetActiveIndex(AValue: String);
|
procedure SetActiveIndex(AValue: String);
|
||||||
procedure SetIndexes(AValue: TJSONIndexDefs);
|
procedure SetIndexes(AValue: TJSONIndexDefs);
|
||||||
procedure SetMetaData(AValue: TJSObject);
|
procedure SetMetaData(AValue: TJSObject);
|
||||||
procedure SetRows(AValue: TJSArray);
|
procedure SetRows(AValue: TJSArray);
|
||||||
procedure SetRowType(AValue: TJSONRowType);
|
procedure SetRowType(AValue: TJSONRowType);
|
||||||
protected
|
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.
|
// Override this to return customized version.
|
||||||
function CreateIndexDefs: TJSONIndexDefs; virtual;
|
function CreateIndexDefs: TJSONIndexDefs; virtual;
|
||||||
// override this to return a customized version if you are so inclined
|
// override this to return a customized version if you are so inclined
|
||||||
@ -287,6 +301,8 @@ type
|
|||||||
procedure InternalCancel; override;
|
procedure InternalCancel; override;
|
||||||
procedure InternalInitFieldDefs; override;
|
procedure InternalInitFieldDefs; override;
|
||||||
procedure InternalSetToRecord(Buffer: TDataRecord); override;
|
procedure InternalSetToRecord(Buffer: TDataRecord); override;
|
||||||
|
procedure SetFilterText(const Value: string); override;
|
||||||
|
procedure SetFiltered(Value: Boolean); override;
|
||||||
function GetFieldClass(FieldType: TFieldType): TFieldClass; override;
|
function GetFieldClass(FieldType: TFieldType): TFieldClass; override;
|
||||||
function IsCursorOpen: Boolean; override;
|
function IsCursorOpen: Boolean; override;
|
||||||
// Bookmark operations
|
// Bookmark operations
|
||||||
@ -1142,13 +1158,112 @@ begin
|
|||||||
FCurrentIndex:=FDefaultIndex;
|
FCurrentIndex:=FDefaultIndex;
|
||||||
end;
|
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;
|
function TBaseJSONDataSet.GetRecord(Var Buffer: TDataRecord; GetMode: TGetMode; DoCheck: Boolean): TGetResult;
|
||||||
|
|
||||||
Var
|
Var
|
||||||
BkmIdx : Integer;
|
BkmIdx : Integer;
|
||||||
|
recordAccepted : Boolean;
|
||||||
begin
|
begin
|
||||||
Result := grOK; // default
|
Result := grOK; // default
|
||||||
|
Repeat
|
||||||
|
recordAccepted:=True;
|
||||||
case GetMode of
|
case GetMode of
|
||||||
gmNext: // move on
|
gmNext: // move on
|
||||||
if fCurrent < fCurrentIndex.Count - 1 then
|
if fCurrent < fCurrentIndex.Count - 1 then
|
||||||
@ -1171,7 +1286,13 @@ begin
|
|||||||
Buffer.BookmarkFlag := bfCurrent;
|
Buffer.BookmarkFlag := bfCurrent;
|
||||||
Buffer.Bookmark:=BkmIdx;
|
Buffer.Bookmark:=BkmIdx;
|
||||||
CalculateFields(Buffer);
|
CalculateFields(Buffer);
|
||||||
|
if Filtered then
|
||||||
|
begin
|
||||||
|
FFilterRow:=Buffer.Data;
|
||||||
|
recordAccepted:=DoFilterRecord;
|
||||||
end;
|
end;
|
||||||
|
end;
|
||||||
|
until recordAccepted;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TBaseJSONDataSet.GetRecordCount: Integer;
|
function TBaseJSONDataSet.GetRecordCount: Integer;
|
||||||
@ -1355,6 +1476,22 @@ begin
|
|||||||
FCurrent:=FCurrentIndex.FindRecord(Integer(Buffer.Bookmark));
|
FCurrent:=FCurrentIndex.FindRecord(Integer(Buffer.Bookmark));
|
||||||
end;
|
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;
|
function TBaseJSONDataSet.GetFieldClass(FieldType: TFieldType): TFieldClass;
|
||||||
begin
|
begin
|
||||||
If UseDateTimeFormatFields and (FieldType in [ftDate,ftDateTime,ftTime]) then
|
If UseDateTimeFormatFields and (FieldType in [ftDate,ftDateTime,ftTime]) then
|
||||||
@ -1445,6 +1582,8 @@ var
|
|||||||
begin
|
begin
|
||||||
if State in [dsCalcFields,dsInternalCalc] then
|
if State in [dsCalcFields,dsInternalCalc] then
|
||||||
R:=CalcBuffer.data
|
R:=CalcBuffer.data
|
||||||
|
else if (State=dsFilter) then
|
||||||
|
R:=FFilterRow
|
||||||
else if (FEditIdx=Buffer.Bookmark) then
|
else if (FEditIdx=Buffer.Bookmark) then
|
||||||
begin
|
begin
|
||||||
if State=dsOldValue then
|
if State=dsOldValue then
|
||||||
@ -1525,6 +1664,7 @@ end;
|
|||||||
|
|
||||||
destructor TBaseJSONDataSet.Destroy;
|
destructor TBaseJSONDataSet.Destroy;
|
||||||
begin
|
begin
|
||||||
|
FreeAndNil(FFilterExpression);
|
||||||
FreeAndNil(FIndexes);
|
FreeAndNil(FIndexes);
|
||||||
FEditIdx:=-1;
|
FEditIdx:=-1;
|
||||||
FreeData;
|
FreeData;
|
||||||
|
Loading…
Reference in New Issue
Block a user