The current SelectQuery class only supports AND operator when creating the query string. Would be good to also allow the OR operator and it is also a very easy way to accomplish this.

CommentFileSizeAuthor
#15 select-interface.patch2.1 KBcwcorrigan
#2 2879844-2.patch642 bytesjzavrl
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

jzavrl created an issue. See original summary.

jzavrl’s picture

Status: Needs work » Needs review
FileSize
642 bytes

Attached patch.

AaronBauman’s picture

This can be accomplished by adding conditions to SelectQuery->conditions property directly.
For example:

$query = new SelectQuery('MyObj__c');
$query->conditions[] = ["Foo = 'bar' OR (zee = 'bang' and foobar > 1)"]

Maybe all that's needed is better documentation for this kind of usage?

Also, if you're using Salesforce Pull, you can use the Pull query SOQL "Where" clause feature to inject any arbitrary SOQL where conditions you need to.

jzavrl’s picture

Status: Needs review » Needs work

Oh... :)

Then it's a good thing the patch only consisted of 2 lines, so I didn't really spend too much time on this :)

But either way, I think that the SelectQuery definitely needs a better documentation on this. I've had no idea you could add a condition like that, since the method is described as addCondition($field, $value, $operator = '=').

Even so, the use of public properties is discouraged by Drupal's coding standards, and we should use public methods for setting/getting the property values.

But for now, I think a better documentation of the SelectQuery method would come a long way. I'll put this together. Also, I feel that the changes from the patch could stay. They give you the flexibility to use a different operator when adding conditions with the addCondition() method, and the property also has a default value, so it wouldn't be breaking backwards compatibility.

Thoughts?

AaronBauman’s picture

I agree that the current "everything is public" isn't a great approach.
Are we headed towards creating a database abstraction layer here?
I couldn't find any robust PHP solutions, but this node module is headed in the right direction: https://github.com/jsforce/jsforce/blob/63c94d30cbdc314444f8f6f113674b89...

Anyway, more documentation on existing features would be great.

acrosman’s picture

D8 core's Database Select class allows pretty wide-open access, and awhile back I ran into frustration with the fact that SearchAPI's equivalent for Solr does not. Which means to modify views that have similar needs but could be a Solr search query or a database interface query you end up having to write the same alterations in two very different ways. Obviously that's a rare use case, but it would be nice if the patterns in this module matched something else in the code base both in terms of methods and data structures. Personally I'd mirror Select and justify any extra public variables by saying it's better to be consistent with core than architecturally perfect.

AaronBauman’s picture

Title: Allow AND/OR operators in SelectQuery » Update SelectQuery interface to closely resemble core database API
Category: Feature request » Task

Yup. Would like to get this done for 8.x-4.x

AaronBauman’s picture

Version: 8.x-3.x-dev » 8.x-4.x-dev
AaronBauman’s picture

Updated version to 8.x-4.x for API changes.
If there non-breaking changes, we can get those into 3.x, but assuming that there will be some major stuff that will need to go to 4.x

cwcorrigan’s picture

Assigned: Unassigned » cwcorrigan
AaronBauman’s picture

Component: Code » salesforce_example.module

Here's the complete set of methods and inherited methods from core's SelectInterface.

Let's start off by identifying which make sense for SOQL:

 addTag($tag);
 hasTag($tag);
 hasAllTags();
 hasAnyTag();
 addMetaData($key, $object);
 getMetaData($key);
 condition($field, $value = NULL, $operator = '=');
 where($snippet, $args = []);
 isNull($field);
 isNotNull($field);
 exists(SelectInterface $select);
 notExists(SelectInterface $select);
 alwaysFalse();
 conditions();
 arguments();
 compile(Connection $connection, PlaceholderInterface $queryPlaceholder);
 compiled();
 conditionGroupFactory($conjunction = 'AND');
 andConditionGroup();
 orConditionGroup();
 extend($extender_name);
 uniqueIdentifier();
 nextPlaceholder();
 getFields();
 getExpressions();
 getOrderBy();
 getGroupBy();
 getTables();
 getUnion();
 escapeLike($string);
 escapeField($string);
 getArguments(PlaceholderInterface $queryPlaceholder = NULL);
 distinct($distinct = TRUE);
 addField($table_alias, $field, $alias = NULL);
 fields($table_alias, array $fields = []);
 addExpression($expression, $alias = NULL, $arguments = []);
 join($table, $alias = NULL, $condition = NULL, $arguments = []);
 innerJoin($table, $alias = NULL, $condition = NULL, $arguments = []);
 leftJoin($table, $alias = NULL, $condition = NULL, $arguments = []);
 rightJoin($table, $alias = NULL, $condition = NULL, $arguments = []);
 addJoin($type, $table, $alias = NULL, $condition = NULL, $arguments = []);
 orderBy($field, $direction = 'ASC');
 orderRandom();
 range($start = NULL, $length = NULL);
 union(SelectInterface $query, $type = '');
 groupBy($field);
 countQuery();
 isPrepared();
 preExecute(SelectInterface $query = NULL);
 execute();
 havingCondition($field, $value = NULL, $operator = NULL);
 havingConditions();
 havingArguments();
 having($snippet, $args = []);
 havingCompile(Connection $connection);
 havingIsNull($field);
 havingIsNotNull($field);
 havingExists(SelectInterface $select);
 havingNotExists(SelectInterface $select);
 __clone();
 forUpdate($set = TRUE);
 __toString();
AaronBauman’s picture

Component: salesforce_example.module » salesforce.module
cwcorrigan’s picture

I think most/all of these could do something to translate to an equivalent but not all of them have a 'native' implementation in SOQL.

  • distinct() - Can't run a distinct query in SOQL have to Group on something
  • orderRandom() - I don't think there's anything implemented to do this
  • union() - No unions but could probably do something to mimic it
  • isNull() - This is just a stanard where clause in SOQL comparing to null there's no built in isNull function or parameter as far as I know. We could obviously implement it as such.
  • isNotNull() - Same as above
AaronBauman’s picture

A few more we may wish to reconsider:
addTag($tag);
hasTag($tag);
hasAllTags();
hasAnyTag();
addMetaData($key, $object);
getMetaData($key);
alwaysFalse
compile
compiled
preexecute
prepared
execute
join($table, $alias = NULL, $condition = NULL, $arguments = []);
innerJoin($table, $alias = NULL, $condition = NULL, $arguments = []);
leftJoin($table, $alias = NULL, $condition = NULL, $arguments = []);
rightJoin($table, $alias = NULL, $condition = NULL, $arguments = []);
addJoin($type, $table, $alias = NULL, $condition = NULL, $arguments = []);
arguments();
uniqueIdentifier();
nextPlaceholder();

I'm not sure how well subquery/parent query will adapt to the "join" API.
We might want to consider breaking compatibility there as well.

Tags, metadata, compile, prepare - these don't seem particularly useful.

Execute() is an interesting case, and got me thinking about how to refactor the whole framework to work more like the Database API...

cwcorrigan’s picture

FileSize
2.1 KB

Potential Interface based on the first pass

cwcorrigan’s picture

AaronBauman’s picture

Status: Needs work » Needs review

I may have gone a bit overboard with these changes, but they've gotten a bit too large to manage with the patch workflow.
I posted a PR at https://github.com/messageagency/sfd8/pull/9 for review

When we're happy with the scope, we can put a patch back up here to appease testbot.

Status: Needs review » Needs work

The last submitted patch, 15: select-interface.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

AaronBauman’s picture

Here's what's included to mimic core, generally (not exhaustive):
- tables
- expressions
- conditions
though we're using conditions to collect our condition expressions, Drupal's compilation doesn't make sense for SOQL. So, there's a compilation step within the Select class itself. Not the most elegant. We may wish to consider a new Condition class specifically for SOQL.
- having
- order by
- limit
- offset
- group by
- subquery expressions
- subquery conditions

Here's what's excluded generally:
- aliases
aliases are supported for tables, so that's included. But only aggregate expressions support aliasing, so I've omitted explicit support for field aliasing. (And it seems like even aggregate experssion aliases are ignored in results anyway).
- arguments and placeholder substitution
Drupal's database layer relies on PHP PDO for placeholder and argument substitution, and no such analog exists to support Salesforce. In theory, we could rebuild such a feature for Salesforce, but I don't think that's in scope here. For now, we'll continue to rely on callers to properly escape, quote, parenthesize, etc.
- joins
Salesforce equivalents of joins may be achieved with subquery expressions.
- unions
- distinct
- tags
- metadata
- comments

And finally there are a number of SOQL specific features which I've not yet implemented, like FOR REFERENCE, TRACKING|VIEWSTAT, DATA CATEGORY, USING SCOPE. Patches to include these are welcome, but shouldn't block committing this changeset.

cwcorrigan’s picture

Assigned: cwcorrigan » Unassigned
AaronBauman’s picture

Status: Needs work » Closed (outdated)

I'm doing some cleanup on unsupported branches.
Please re-open this issue and update the version to 5.0.x-dev if this issue is still applicable to the latest release.