[SalesForce] System.QueryException unexpected token

Trying to return all fields in object

System.QueryException: unexpected token: '('

when I run the Invocable class at the parents = assignment

public with sharing class AuditReportBulkifyClass {

    @InvocableMethod(label='Collect Bulkified Records')
    public static List<List<hdone__AuditReport__c>> gatherRequests(Request[] requests) {

        // Gather bulkified records from Flow
        Map<Id, hdone__AuditReport__c> parents = new Map<Id, hdone__AuditReport__c>();

        // Want to get all fields from object for use in Flows
        Map<String, Schema.SobjectField> fieldMap = hdone__AuditReport__c.SobjectType.getDescribe().fields.getMap();
        Set<String> fieldNames = fieldMap.keySet();
        String myset_Joined = string.join(new List<String>(fieldNames), ',');
        String theQuery = 'SELECT ' + myset_Joined + ' FROM hdone__AuditReport__c WHERE Id IN :parents.keySet()';

        for(Request request : requests) {
            parents.put(request.recordId, null);
        }

        parents = new Map<Id, hdone__AuditReport__c>(
            (List<hdone__AuditReport__c>)Database.query(theQuery)
        );

        // Flows must return List<List> for Sobject Collections. This is returned as Sobject Collection to Flow
        List<List<hdone__AuditReport__c>> responseColl = new List<List<hdone__AuditReport__c>>();

        // Add all of the values to an initial List
        List<hdone__AuditReport__c> responseList = new List<hdone__AuditReport__c>();
        responseList.addAll(parents.values());

        System.debug('Size of ResponseList ' + responseList.size());

        // Adds actual values we will use to the List of List
        responseColl.add(responseList);
        System.debug('Return responseColl size ' + responseColl.size());

        // Initialize a new list which will return empty to ensure return same number of interviews back to Flow
        List<hdone__AuditReport__c> emptyList = new List<hdone__AuditReport__c>();

        // Iterate through number of interviews - 1 and assign to empty list
        for (Integer i=0; i<responseList.size()-1; i++){
            responseColl.add(emptyList);
            }
        return responseColl;
    }

    public with sharing class Request {
        @InvocableVariable(label='Record ID' required=true)
        public Id recordId;

        @InvocableVariable(label='Object API Name' required=false)
        public String objectName;

        @InvocableVariable(label='Parent ID' required=false)
        public Id parentId;
    }
}

Best Answer

There are some variable bindings that "normal" SOQL can resolve, but Dynamic SOQL cannot.

It's probably not a perfect rule, but if your variable binding includes a period/dot/full-stop like you have in parents.keySet(), then chances are that it won't work with Dynamic SOQL.

See the "Dynamic SOQL Considerations" section of the documentation on dynamic SOQL for a better idea of what, precisely, is and is not allowed.

The solution here is to store your parents.keySet() in a dedicated variable of type Set<Id> sometime prior to when you need it in your dynamic query. You could probably use String.format() somehow as well.