This
blog series follows the journey of building the new and improved
Interactive Google Ads Query Builder tool.
Part 5 of this series described how we determine whether or not a field is selectable. In Part 6, we will discuss how we add fields to a Google Ads Query Language (GAQL) string using the
SelectionService
.
GAQL String State
In order to track which fields have been selected, we need to keep track of the GAQL string’s state, which we can do in an instance variable called
selectedFields
that has the following interface definition:
interface SelectedFields {
select: string[];
where: Array<{field: string, context: string}>;
orderBy: Array<{field: string, context?: string}>;
limit?: string;
params?: string;
}
The
select
field holds an array of field names. The
where
field holds an array of objects, each of which contains a
field
name and
context
string. By context, we mean the filtering condition to apply to the field (or operator and operand). For example, if we added the filtering condition,
ad_group.id = 1234567890
to the WHERE clause, the field would be
ad_group.id
, and the context would be
= 1234567890.
Similarly, the
orderBy
field holds an array of
field
names and optional
context
strings. Here,
context
is the optional ASC or DESC direction (default ASC). The
limit
field is the optional string representation of the integer
LIMIT. Finally, the optional
params
field represents the optional string value of the
PARAMETERS clause. We don’t need an array here because there is currently only a single option for this clause.
Selecting Fields
Now that we have a data structure in place to track the state of a user’s query, we can implement a method to select a field in any clause.
selectField(field: string, clause: string, context?: string): void {
...
}
If the
clause
is SELECT, we’ll add the provided field to the
select
array in
selectedFields
. When users add a field in the SELECT clause, no context is provided.
If the
clause
is WHERE, all three parameters are required because a filtering condition containing an operator and operand must be provided as a
context
string. When users click the checkbox to add a field in the WHERE clause, we’ll open a dialog prompting them to specify the operator, and then an operand once the operator has been set. Depending on the
data_type
of the field being selected, we’ll pre-populate the list of available operators a user can select, and depending on the operator selected, we’ll show the user a different component to input the operand. Once a user adds the filtering criteria, we’ll join the operator and operand into a single string to create the
context
string.

If the
clause
is ORDER BY,
context
is optional. When a user selects a field in the ORDER BY clause, we’ll call
selectField
without any context and add the field to the
orderBy
array of
selectedFields
without any context. We’ll also present users with radio buttons under the field name to specify an order of ASC or DESC. Upon clicking one of the options, we’ll update the respective field’s entry in the
orderBy
array to add the order
context
.

If the
clause
is LIMIT or PARAMETERS, we’ll update the
limit
and
params
entries of
selectedFields
, respectively, with the provided string as the
field
parameter. The limit must be a positive integer, the validation for which is performed in the related UI component. The only parameter currently available is
include_drafts
, and the default value is false. Therefore, we’ll present users with a checkbox in the UI component for PARAMETERS with a single option ‘include_drafts=true’. If the user clicks the checkbox, we’ll pass the string
include_drafts=true
to
selectField
as the
field
.
SELECT Presence
While the logic of selecting fields is straight-forward, there are two rules regarding selectability that we intentionally skipped in
part 5. Certain fields must be present in the SELECT clause before they can be inserted into the WHERE or ORDER BY clauses.
Rule #1: with the exception of “core date segments” (segments.date, segments.week, segments.month, segments.quarter, segments.year), all segments and segmenting resources must be present in the SELECT clause before they can be inserted into the WHERE clause.Rule #2: all segments, segmenting resources, metrics, and attributed resource fields must be present in the SELECT clause before they can be inserted into the ORDER BY clause. In other words, only fields on the resource in the FROM clause can be placed in the ORDER BY clause without first being inserted into the SELECT clause.In these cases, we’ll present a dialog that enables the user to add the field to the SELECT clause as well as the desired clause in a single step.

Deselecting Fields
In order to deselect fields, we’ll implement a method in the
SelectionService
called
deselectField
.
deselectField(field: string, clause: string): void {
…
}
Deselecting a field is similar to selecting a field. As a safeguard, we’ll first check if the field is selected. Then, if the
clause
is SELECT, WHERE, or ORDER BY, we’ll remove the deselected field from the respective array entry of
selectedFields
. In the event the field that is required to be present in SELECT before being added to WHERE or ORDER BY according to the rules described above and is removed from SELECT, we’ll automatically remove the field from SELECT in a single operation. If the clause is LIMIT or PARAMETERS, we’ll update the respective entry of
selectedFields
to
undefined
.
Updating the Output
With the
selectedFields
variable,
selectField
method, and
deselectField
method in place, we can now track the state of the query string. In order to keep track of changes throughout the application, we’ll create an
Observable in the
SelectionService
and call
next
on it each time
selectField
or
deselectField
is called. Then, we can subscribe to the observable in any component that needs to be aware of the GAQL query state.
Conclusion
We have now updated the
SelectionService
to select fields and deselect fields. In this post, we’ve covered:
- GAQL query and clause structure.
- Additional detail regarding selectability.
- Using Observables in Angular.
Hopefully this has deepened your understanding of constructing GAQL queries with the Google Ads API. If you have any questions or need additional help, contact us via the
forum or at
[email protected].
- Devin Chasanoff, on behalf of the Google Ads API Team