FB4D Reference IStructuredQuery - SchneiderInfosystems/FB4D GitHub Wiki

Interface IStructuredQuery

This interface allows creating a query for retrieve data from the Firestore Database. The interface will be created by the class function TStructuredQuery.CreateForCollection in the unit FB4D.Firestore.

This interface supports a fluent interface design. That is why the methods QueryForFieldFilter and QueryForCompositeFilter can be called in cascades because they return the caller interface for adding the next query.

The following sample illustrates how simple a query can build for retrieve all nodes of MyCollection that contains a sub-node MyValue which fits the content in the string variable SearchValue.

var
  Database: IFirestoreDatabase;
begin
  Database.RunQuery(
    TStructuredQuery.CreateForCollection('MyCollection').QueryForFieldFilter(
      TQueryFilter.StringFieldFilter('MyAttribute', woEqual, SearchValue:string)),
    OnDocuments, OnRequestError);

The above query fits the following demo data. For a SearchValue red the document with the ID 2MPuHwXjoMUuVeU9f34e will be returned:

Firebase console shows demo data for query example

The method QueryForCompositeFilter allows combining several IQueryFilter by applying the logical And operator.

The following example shows a simple composite query for the search term: (MyAttribute='red') and (MyVal <= 5.0)

Database.RunQuery(
  TStructuredQuery.CreateForCollection('MyCollection').QueryForCompositeFilter(
    coAnd,
    [TQueryFilter.StringFieldFilter('MyAttribute', woEqual, 'red'),
     TQueryFilter.BooleanFieldFilter('MyVal', woLessThan, 5.0)]),
  OnDocuments, OnRequestError)

If you do not need the entire document, you can use IStructuredQuery.Select(FieldRefs: TRequestResourceParam) and pass only a list of field names. For better code, there is also a class method TStructuredQuery.CreateForSelectimplemented that creates an IStructuredQuery and call the method select as first:

Database.RunQuery(
  TStructuredQuery.CreateForSelect(['MyField1', 'MyField2', 'MyField3']).
    Collection('MyCollection'));

According to the SQL select statement, there is an order-by method:

function IStructuredQuery.OrderBy(const FieldRef: string;
  Direction: TOrderDirection): IStructuredQuery;

Whereas TOrderDirection has the following options odAscending or odDescending.

When you have more than one sort order level, call this OrderBy level by level with the field name and its sort order direction.

Because the Delphi class interface uses automatic reference counting ARC you do not need manually to get free the created instances of IQueryFilter and IStructuredQuery. This enables the efficient fluent interface design, which after having created the structured query by CreateForSelect, loops it through several filter functions such as Collection followed by OrderBy.

Database.RunQuery(
  TStructuredQuery.CreateForSelect(['MyField1', 'MyField2', 'MyField3']).
    Collection('MyCollection').
    OrderBy('MyField1', odDescending));

In order to fetch only a subset of the resulting document set the method Limit allows passing a maximal number of documents and the method Offset let to define the first returned document.

function IStructuredQuery.Limit(limit: integer): IStructuredQuery;
function IStructuredQuery.Offset(offset: integer): IStructuredQuery;

Additionally, the Firestore offers a second approach to do the same thing: With StartAt and EndAt you can pass a start document and an end document in the parameter Cursor.

function IStructuredQuery.StartAt(Cursor: IFirestoreDocument; Before: boolean): IStructuredQuery;
function IStructuredQuery.EndAt(Cursor: IFirestoreDocument; Before: boolean): IStructuredQuery;

The parameter Before defines if the position is just before or just after the given cursor, relative to the sort order defined by the query.