}
}
+ /**
+ * @param string $fieldName
+ * @param string $op
+ * @param mixed $value
+ * @param bool $isExpression
+ * @return $this
+ * @throws \API_Exception
+ */
+ public function addWhere(string $fieldName, string $op, $value = NULL, bool $isExpression = FALSE) {
+ if (!in_array($op, CoreUtil::getOperators())) {
+ throw new \API_Exception('Unsupported operator');
+ }
+ $this->where[] = [$fieldName, $op, $value, $isExpression];
+ return $this;
+ }
+
/**
* @return array
*/
/**
* Validate and transform a leaf clause array to SQL.
- * @param array $clause [$fieldName, $operator, $criteria]
+ * @param array $clause [$fieldName, $operator, $criteria, $isExpression]
* @param string $type
* WHERE|HAVING|ON
* @param int $depth
$field = NULL;
// Pad array for unary operators
[$expr, $operator, $value] = array_pad($clause, 3, NULL);
+ $isExpression = $clause[3] ?? FALSE;
if (!in_array($operator, CoreUtil::getOperators(), TRUE)) {
throw new \API_Exception('Illegal operator');
}
// For WHERE clause, expr must be the name of a field.
- if ($type === 'WHERE') {
+ if ($type === 'WHERE' && !$isExpression) {
$field = $this->getField($expr, TRUE);
FormattingUtil::formatInputValue($value, $expr, $field, $operator);
$fieldAlias = $this->getExpression($expr)->render($this->apiFieldSpec);
}
$fieldAlias = '`' . $fieldAlias . '`';
}
- elseif ($type === 'ON') {
+ elseif ($type === 'ON' || ($type === 'WHERE' && $isExpression)) {
$expr = $this->getExpression($expr);
$fieldName = count($expr->getFields()) === 1 ? $expr->getFields()[0] : NULL;
$fieldAlias = $expr->render($this->apiFieldSpec);
--- /dev/null
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved. |
+ | |
+ | This work is published under the GNU AGPLv3 license with some |
+ | permitted exceptions and without any warranty. For full license |
+ | and copyright information, see https://civicrm.org/licensing |
+ +--------------------------------------------------------------------+
+ */
+
+namespace Civi\Api4\Query;
+
+/**
+ * Sql function
+ */
+class SqlFunctionBINARY extends SqlFunction {
+
+ protected static $category = self::CATEGORY_STRING;
+
+ protected static function params(): array {
+ return [
+ [
+ 'optional' => FALSE,
+ 'must_be' => ['SqlField', 'SqlString'],
+ ],
+ ];
+ }
+
+ /**
+ * @return string
+ */
+ public static function getTitle(): string {
+ return ts('Binary');
+ }
+
+}
$this->assertEquals(['Student'], $result['Contact_RelationshipCache_Contact_01.contact_sub_type:label']);
}
+ public function testGetWithWhereExpression() {
+ $last_name = uniqid(__FUNCTION__);
+
+ $alice = Contact::create()
+ ->setValues(['first_name' => 'Alice', 'last_name' => $last_name])
+ ->execute()->first();
+
+ $result = Contact::get(FALSE)
+ ->addWhere('last_name', '=', $last_name)
+ ->addWhere('LOWER(first_name)', '=', "BINARY('ALICE')", TRUE)
+ ->execute()->indexBy('id');
+ $this->assertCount(0, $result);
+
+ $result = Contact::get(FALSE)
+ ->addWhere('last_name', '=', $last_name)
+ ->addWhere('LOWER(first_name)', '=', "BINARY('alice')", TRUE)
+ ->execute()->indexBy('id');
+ $this->assertArrayHasKey($alice['id'], (array) $result);
+ }
+
/**
* @throws \API_Exception
*/
$this->assertStringContainsString("Deprecated join alias 'contact' used in APIv4 get. Should be changed to 'contact_id'", $message);
}
+ public function testJoinWithExpression() {
+ Phone::create(FALSE)
+ ->setValues(['contact_id' => $this->getReference('test_contact_1')['id'], 'phone' => '654321'])
+ ->execute();
+ $contacts = Contact::get(FALSE)
+ ->addSelect('id', 'phone.phone')
+ ->addJoin('Phone', 'INNER', ['LOWER(phone.phone)', '=', "CONCAT('6', '5', '4', '3', '2', '1')"])
+ ->addWhere('id', 'IN', [$this->getReference('test_contact_1')['id'], $this->getReference('test_contact_2')['id']])
+ ->addOrderBy('phone.id')
+ ->execute();
+ $this->assertCount(1, $contacts);
+ $this->assertEquals($this->getReference('test_contact_1')['id'], $contacts[0]['id']);
+ $this->assertEquals('654321', $contacts[0]['phone.phone']);
+ }
+
}
$this->assertEquals(100, $result[0]['MIN:total_amount']);
$this->assertEquals(2, $result[0]['count']);
$this->assertEquals(1, $result[1]['count']);
+
+ $result = Contribution::get(FALSE)
+ ->addGroupBy('contact_id')
+ ->addGroupBy('receive_date')
+ ->addSelect('contact_id')
+ ->addSelect('receive_date')
+ ->addSelect('SUM(total_amount)')
+ ->addOrderBy('receive_date')
+ ->addWhere('contact_id', '=', $cid)
+ ->addHaving('SUM(total_amount)', '>', 300)
+ ->execute();
+ $this->assertCount(1, $result);
+ $this->assertStringStartsWith('2020-04-04', $result[0]['receive_date']);
+ $this->assertEquals(400, $result[0]['SUM:total_amount']);
}
public function testComparisonFunctions() {