unit XData.Criteria.ProjectionVisitor;

interface

uses
  Generics.Collections,
  Aurelius.Criteria.Base,
  XData.Query.Expression;

type
  TQueryProjectionVisitor = class(TStackQueryVisitor<TSimpleProjection>)
  public
    procedure NullLiteral(const Expr: TNullLiteralExpression); override;
    procedure StringLiteral(const Expr: TStringLiteralExpression); override;
    procedure DateTimeLiteral(const Expr: TDateTimeLiteralExpression); override;
    procedure GuidLiteral(const Expr: TGuidLiteralExpression); override;
    procedure DoubleLiteral(const Expr: TDoubleLiteralExpression); override;
    procedure IntegerLiteral(const Expr: TIntegerLiteralExpression); override;
    procedure Int64Literal(const Expr: TInt64LiteralExpression); override;
    procedure BooleanLiteral(const Expr: TBooleanLiteralExpression); override;
    procedure Logical(const Expr: TLogicalExpression); override;
    procedure Comparison(const Expr: TComparisonExpression); override;
    procedure Arithmetic(const Expr: TArithmeticExpression); override;
    procedure ArithmeticUnary(const Expr: TArithmeticUnaryExpression); override;
    procedure Parenthesis(const Expr: TParenthesisExpression); override;
    procedure Member(const Expr: TMemberExpression); override;
    procedure MethodCall(const Expr: TMethodCallExpression); override;
    procedure BooleanUnary(const Expr: TBooleanUnaryExpression); override;
    procedure ResolvedMember(const Expr: TResolvedMemberExpression); override;
  end;

implementation

uses
  System.TypInfo,
  Aurelius.Criteria.Projections,
  XData.Query.Exceptions;

{ TQueryProjectionVisitor }

procedure TQueryProjectionVisitor.Arithmetic(const Expr: TArithmeticExpression);
begin
  raise EQueryUnsupportedProjection.Create(Expr);
end;

procedure TQueryProjectionVisitor.ArithmeticUnary(const Expr: TArithmeticUnaryExpression);
begin
  raise EQueryUnsupportedProjection.Create(Expr);
end;

procedure TQueryProjectionVisitor.BooleanLiteral(const Expr: TBooleanLiteralExpression);
begin
  Push(TProjections.Value<boolean>(Expr.Value));
end;

procedure TQueryProjectionVisitor.BooleanUnary(const Expr: TBooleanUnaryExpression);
begin
  raise EQueryUnsupportedProjection.Create(Expr);
end;

procedure TQueryProjectionVisitor.Comparison(const Expr: TComparisonExpression);
begin
  raise EQueryUnsupportedProjection.Create(Expr);
end;

procedure TQueryProjectionVisitor.DateTimeLiteral(const Expr: TDateTimeLiteralExpression);
begin
  Push(TProjections.Value<TDateTime>(Expr.Value));
end;

procedure TQueryProjectionVisitor.DoubleLiteral(const Expr: TDoubleLiteralExpression);
begin
  Push(TProjections.Value<double>(Expr.Value));
end;

procedure TQueryProjectionVisitor.GuidLiteral(const Expr: TGuidLiteralExpression);
begin
  Push(TProjections.Value<TGuid>(Expr.Value));
end;

procedure TQueryProjectionVisitor.Int64Literal(const Expr: TInt64LiteralExpression);
begin
  Push(TProjections.Value<Int64>(Expr.Value));
end;

procedure TQueryProjectionVisitor.IntegerLiteral(const Expr: TIntegerLiteralExpression);
begin
  Push(TProjections.Value<Integer>(Expr.Value));
end;

procedure TQueryProjectionVisitor.Logical(const Expr: TLogicalExpression);
begin
  raise EQueryUnsupportedProjection.Create(Expr);
end;

procedure TQueryProjectionVisitor.Member(const Expr: TMemberExpression);
begin
  raise EQueryUnsupportedProjection.Create(Expr);
end;

type
  TInternalProjection = class(TProjection)
  end;

procedure TQueryProjectionVisitor.MethodCall(const Expr: TMethodCallExpression);
var
  I: integer;
  Args: TArray<TSimpleProjection>;
begin
  // Process input arguments and transform them into projections
  for I := Expr.Arguments.Count - 1 downto 0 do
    Expr.Arguments[I].Accept(Self);

  // Flll the projection array for arguments
  SetLength(Args, Expr.Arguments.Count);
  for I := 0 to Length(Args) - 1 do
    Args[I] := Pop;

  // Push the SQL function projection
  Push(TSQLFunctionProjection.Create(Expr.Method.SQLFunctionName, nil, Args));
end;

procedure TQueryProjectionVisitor.NullLiteral(const Expr: TNullLiteralExpression);
begin
  Push(TNullProjection.Create);
end;

procedure TQueryProjectionVisitor.Parenthesis(const Expr: TParenthesisExpression);
begin
  Expr.Expression.Accept(Self);
end;

procedure TQueryProjectionVisitor.ResolvedMember(const Expr: TResolvedMemberExpression);
begin
  Push(TProjections.Prop(Expr.FullName));
end;

procedure TQueryProjectionVisitor.StringLiteral(const Expr: TStringLiteralExpression);
begin
  Push(TProjections.Value<string>(Expr.Value));
end;

end.
