unit XData.Criteria.ExpandVisitor;

interface

uses
  Generics.Collections,
  Bcl.Collections,
  Aurelius.Criteria.Base,
  XData.Aurelius.Model,
  XData.Model.Classes,
  XData.Query.Expression,
  XData.Criteria.AliasVisitor;

type
  TQueryAliasExpandVisitor = class(TStackQueryVisitor<TQueryExpression>)
  strict private
    FModel: TXDataAureliusModel;
    FType: TXDataEntityType;
    FAliases: TQueryAliases;
  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;
  public
    constructor Create(const AModel: TXDataAureliusModel; AType: TXDataEntityType;
      AAliases: TQueryAliases);
    destructor Destroy; override;
    property Aliases: TQueryAliases read FAliases;
  end;

  TQueryExpandVisitor = class(TQueryVisitor)
  strict private
    FModel: TXDataAureliusModel;
    FType: TXDataEntityType;
    FExpandProps: THashSet<TXDataProperty>;
  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;
  public
    constructor Create(const AModel: TXDataAureliusModel; AType: TXDataEntityType;
      AExpandProps: THashSet<TXDataProperty>);
    destructor Destroy; override;
  end;

implementation

uses
  SysUtils,
  XData.Query.Exceptions;


{ TQueryExpandVisitor }

procedure TQueryAliasExpandVisitor.Arithmetic(const Expr: TArithmeticExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryAliasExpandVisitor.ArithmeticUnary(
  const Expr: TArithmeticUnaryExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryAliasExpandVisitor.BooleanLiteral(const Expr: TBooleanLiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryAliasExpandVisitor.BooleanUnary(const Expr: TBooleanUnaryExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryAliasExpandVisitor.Comparison(const Expr: TComparisonExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

constructor TQueryAliasExpandVisitor.Create(const AModel: TXDataAureliusModel;
  AType: TXDataEntityType; AAliases: TQueryAliases);
begin
  inherited Create;
  FModel := AModel;
  FType := AType;
  FAliases := AAliases;
end;

procedure TQueryAliasExpandVisitor.DateTimeLiteral(const Expr: TDateTimeLiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

destructor TQueryAliasExpandVisitor.Destroy;
begin
  inherited;
end;

procedure TQueryAliasExpandVisitor.DoubleLiteral(const Expr: TDoubleLiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryAliasExpandVisitor.GuidLiteral(const Expr: TGuidLiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryAliasExpandVisitor.Int64Literal(const Expr: TInt64LiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryAliasExpandVisitor.IntegerLiteral(const Expr: TIntegerLiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryAliasExpandVisitor.Logical(const Expr: TLogicalExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryAliasExpandVisitor.Member(const Expr: TMemberExpression);
var
  PathAlias: string;
  PathMember: string;
  NavProp: TXDataNavigationProperty;
  NavPath: TNavPath;
begin
  // Get the list of properties that makes up the full property path
  NavPath := TNavPath.CreatePath(Self.FType, Expr.Names);

  // Set alias for fetch mode, either if it exists or not (then create it)
  PathAlias := '';
  for NavProp in NavPath.NavProps do
  begin
    // if it's a collection, do not add alias further in the path
    if NavProp.Target.IsCollection then Exit;

    PathMember := FModel.GetNavPropInfo(NavProp).MemberName;
    PathAlias := FAliases.AddOrSet(PathAlias, PathMember, NavProp, TFetchMode.Eager).Alias;
  end;

//  if NavPath.FinalProp is TXDataSimpleProperty then
//    PathMember := FModel.GetPropertyInfo(TXDataSimpleProperty(NavPath.FinalProp)).RttiInfo.MemberName
//  else
//    PathMember := FModel.GetPropertyAssociation(TXDataNavigationProperty(NavPath.FinalProp)).Optimization.MemberName;

  if NavPath.FinalProp is TXDataNavigationProperty then
  begin
    NavProp := TXDataNavigationProperty(NavPath.FinalProp);

    if NavProp.Target.IsCollection then Exit;
    PathMember := FModel.GetNavPropInfo(NavProp).MemberName;
    PathAlias := FAliases.AddOrSet(PathAlias, PathMember, NavProp, TFetchMode.Eager).Alias;
  end;
end;

procedure TQueryAliasExpandVisitor.MethodCall(const Expr: TMethodCallExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryAliasExpandVisitor.NullLiteral(const Expr: TNullLiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryAliasExpandVisitor.Parenthesis(const Expr: TParenthesisExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryAliasExpandVisitor.ResolvedMember(
  const Expr: TResolvedMemberExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryAliasExpandVisitor.StringLiteral(
  const Expr: TStringLiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

{ TQueryAliasVisitor }

procedure TQueryExpandVisitor.Arithmetic(const Expr: TArithmeticExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryExpandVisitor.ArithmeticUnary(
  const Expr: TArithmeticUnaryExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryExpandVisitor.BooleanLiteral(
  const Expr: TBooleanLiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryExpandVisitor.BooleanUnary(const Expr: TBooleanUnaryExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryExpandVisitor.Comparison(const Expr: TComparisonExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

constructor TQueryExpandVisitor.Create(const AModel: TXDataAureliusModel;
  AType: TXDataEntityType; AExpandProps: THashSet<TXDataProperty>);
begin
  FModel := AModel;
  FType := AType;
  FExpandProps := AExpandProps;
end;

procedure TQueryExpandVisitor.DateTimeLiteral(
  const Expr: TDateTimeLiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

destructor TQueryExpandVisitor.Destroy;
begin
  inherited;
end;

procedure TQueryExpandVisitor.DoubleLiteral(
  const Expr: TDoubleLiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryExpandVisitor.GuidLiteral(const Expr: TGuidLiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryExpandVisitor.Int64Literal(const Expr: TInt64LiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryExpandVisitor.IntegerLiteral(
  const Expr: TIntegerLiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryExpandVisitor.Logical(const Expr: TLogicalExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryExpandVisitor.Member(const Expr: TMemberExpression);
var
  NavPath: TNavPath;
  NavProp: TXDataNavigationProperty;
begin
  NavPath := TNavPath.CreatePath(Self.FType, Expr.Names);
  if not (NavPath.FinalProp is TXDataNavigationProperty) then
    raise EQueryInvalidExpand.Create(NavPath.FinalProp.Name);

  for NavProp in NavPath.NavProps do
    FExpandProps.Add(NavProp);
  FExpandProps.Add(NavPath.FinalProp);
end;

procedure TQueryExpandVisitor.MethodCall(const Expr: TMethodCallExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryExpandVisitor.NullLiteral(const Expr: TNullLiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryExpandVisitor.Parenthesis(const Expr: TParenthesisExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryExpandVisitor.ResolvedMember(
  const Expr: TResolvedMemberExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

procedure TQueryExpandVisitor.StringLiteral(
  const Expr: TStringLiteralExpression);
begin
  raise EQueryUnsupportedExpand.Create(Expr);
end;

end.
