problem with TDateTime function parameter in IRepository

Issue #199 resolved
Sergey Burov created an issue
ICustomRepository = interface(IRepository<TCustomEntity, Integer>)
    ['{4CEFBF25-BAC1-42CD-BCAA-7321D9B4EFED}']
    [Query('select * from t_table where f_date = :0')]
    function FindByDate(const ADate: TDateTime): IList<TCustomEntity>;  
  end;

when we call funciton FindByDate with parameter for example now(), we receive type cast error double to date from postgres.

we found that RTTI invoke this funciton with parameter extended type insted datetime

did you have any solution for this problem?

Comments (15)

  1. Stefan Glienke repo owner

    Look into FromArgsToConstArray - since the parameters are passed as array of TVarRec it loses the exact information that it was a TDateTime and not an Extended. It is not great and passing as TValue array would have been better but this is how it was when we integrated it into Spring4d and I did not refactor it yet. In a future version we might change the related method signatures to array of TValue.

    I am not sure how postgres handles date parameters and in what format it expects them - what you can try is transferring them as string with the correct format. For that add some code to the tkFloat case in the routine i mentioned before.

  2. Inkvizi

    I look into function FromArgsToConstArray(const args: TArray<TValue>): TArray<TVarRec>; In args parameters for example in topic we have args[i].Kind is tkFloat and TVarData(args[i].AsVariant).VType is varDouble.

    How we can find out in this routine that actually args[i] is Date?

  3. Inkvizi

    Is code like this

        tkFloat:
          begin
            if SameText(value.TypeInfo.Name, 'TDate') or (SameText(value.TypeInfo.Name, 'TDateTime')) or
              SameText(value.TypeInfo.Name, 'TTime') then
            begin
              New(item.VVariant);
              item.VVariant^ := value.AsVariant;
              TVarData(item.VVariant^).VType := varDate;
              item.VType := vtVariant;
            end else begin
              New(item.VExtended);
              item.VExtended^ := value.AsExtended;
              item.VType := vtExtended;
            end;
          end;
    

    will be correct to solve this issue? Or maybe it's a better way to wait a change of the related method signatures to array of TValue?

  4. Stefan Glienke repo owner

    Ah, I did not think of using a Variant to transport the information about it being a date - try it and let me know if that solves the issue for you. Also it would be nice if you can test the other postgres types such as time and timestamp as well.

    As for changing the signatures this will not happen before 1.3.

  5. Inkvizi

    I'm try for parameter TDate in Delphi and column type Date in postgres. It's work. I will test other postgres types and write here result.

  6. Inkvizi

    I received next results from tests

    1) For Delphi TDate and Postgres Date - Done

    2) For Delphi TDateTime and Postgres TimeStamp - Done

    3) For Delphi TDateTime and Postgres TimeStampTZ - Done

    4) For Delphi TTime and Postgres Time - Fail with postgres cast exception

    5) For Delphi TTime and Postgres TimeTZ - Fail with postgres cast exception

    For our issue with TDate the solution with variant is suitable. For using TTime in query parameters as temporary solution can be next additional code

        varDate:
        begin
          if ABS(Double(value)) < 1.0  then
            Result := From<TTime>(TVarData(value).VDate)
          else
          begin
            Result := From<TDateTime>(TVarData(value).VDate)
          end;
        end;
    

    In unit Spring class function TValueHelper.FromVariant(const value: Variant): TValue; But this is bad solution. Only for temporary.

  7. Inkvizi

    Is it possible to include array of or IList<T> to permitted function parameters in IRepository? It can be use with IN criteria in queries.

  8. Inkvizi

    For case

     ICustomRepository = interface(IRepository<TCustomEntity, Integer>)
        ['{4CEFBF25-BAC1-42CD-BCAA-7321D9B4EFED}']
        [Query('select * from t_table where f_name in (:0)')]
        function FindByName(const ANameList: IList<string>): IList<TCustomEntity>;  
      end;
    

    or

    ICustomRepository = interface(IRepository<TCustomEntity, Integer>)
        ['{4CEFBF25-BAC1-42CD-BCAA-7321D9B4EFED}']
        [Query('select * from t_table where f_name in (:0)')]
        function FindByName(const ANameList: array of string): IList<TCustomEntity>;  
      end;
    
  9. Log in to comment