Introducing TMS XData Query Builder and more!
We’re excited to announce TMS XData 5.2 version with several new great features. TMS XData is the more straightforward way to take your Delphi app to the cloud, allowing you to create secure, robust REST servers along with a huge ecosystem around it. Here are the major features in this release, which also includes several minor improvements and bug fixes. XData Query Builder XData allows you to easily query entities from automatic entity set endpoints using a full query syntax. For example, to query customers which name is “Paul” or birthday date is lower then August 1st, 1940, ordered by name in descending order, you can write a code like this: Customers := Client.List(‘$filter=(Name eq ”Paul”) or (Birthday lt 1940-08-01)&$orderby=Name desc’); But now you don’t need to worry to write the raw query syntax anymore. The new XData Query Builder allows you to build such filter using a fluent interface which already does some validation (like checking for correct property names) before the data is sent to the server: Customers := Client.List( CreateQuery .From(TCustomer) .Filter( (Linq[‘Name’] = ‘Paul’) or (Linq[‘Birthday’] < EncodeDate(1940, 8, 1)) ) .OrderBy('Name', False) .QueryString ); You can build logical expressions and projections in a similar way you would do with TMS Aurelius criteria. Receive DTO objects in URL query string Service operations can now receive DTOs (Delphi objects) from the query string of the request URL (as long the DTO only have properties of scalar types). In this case, each DTO property will be a separated query param. Suppose you have a class TCustomerDTO which has properties Id and Name, then you can declare the method like this: [HttpGet] function FindByIdOrName(Customer: TCustomerDTO): TList; And have your Customer parameter be received from a request URL like this: GET /CustomerService/FindByIdOrName?Id=10&Name='Paul'. XData queries in service operations Now, in addition to send queries to automatic CRUD entity set endpoints, you can also benefit from XData query mechanism in service operations. You can now easily receive and process XData query syntax like $filter, $orderby, $top and $skip in service operations, even for DTOs, and create Aurelius criteria from it. You can declare a service like this: type IMyService = interface(IInvokable) [HttpGet] function List(Query: TXDataQuery): TList; Which means clients can now invoke the endpoint passing the same $filter, $orderby, $top and $skip parameters, like this: GET /MyService/List/?$filter=Name eq 'Foo'&$orderby=Name&$top=10&$skip=30 Or, of course, passing the raw filter string with TXDataClient: Customer := Client.Service .List('$filter=Name eq 'Foo'&$orderby=Name&$top=10&$skip=30'); Or even using the brand new XData query builder fluent interface: Customer := Client.Service.List( CreateQuery.From(TCustomer) .Filter(Linq['Name'] eq 'Foo') .OrderBy('Name') .Top(10).Skip(30) .QueryString ); From server-side, you can create an Aurelius criteria automatically from the passed XData query: function TMyService.List(Query: TXDataQuery): TList; begin Result := TXDataOperationContext.Current .CreateCriteria(Query).List; end; Not only that, you can even create a criteria from a query based on a DTO object: function TMyService.List(Query: TXDataQuery): TList; begin Result := TXDataOperationContext.Current .CreateCriteria(Query, TCustomerDTO).List; end; In the example above, even though you are creating a criteria for the TCustomer class, the query will be validated based on the TCustomerDTO class. This means XData will only accept queries that use properties from TCustomerDTO. For example, if the filter string is $filter=Status eq 2, even if the Status property exists in TCustomer, if it does not exist in class TCustomerDTO the query will not be accepted and an error "property […]
