Skip to content

Commit 3b9a3a5

Browse files
Merge remote-tracking branch 'upstream/main' into dat-677
2 parents e9706f6 + bfc010c commit 3b9a3a5

File tree

3 files changed

+346
-699
lines changed

3 files changed

+346
-699
lines changed

src/Database/Adapter/MariaDB.php

Lines changed: 3 additions & 353 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace Utopia\Database\Adapter;
44

55
use Exception;
6-
use PDO;
76
use PDOException;
87
use Utopia\Database\Database;
98
use Utopia\Database\Document;
@@ -14,7 +13,6 @@
1413
use Utopia\Database\Exception\Truncate as TruncateException;
1514
use Utopia\Database\Helpers\ID;
1615
use Utopia\Database\Query;
17-
use Utopia\Database\Validator\Authorization;
1816

1917
class MariaDB extends SQL
2018
{
@@ -1363,354 +1361,6 @@ public function deleteDocument(string $collection, string $id): bool
13631361
return $deleted;
13641362
}
13651363

1366-
/**
1367-
* Find Documents
1368-
*
1369-
* @param Document $collection
1370-
* @param array<Query> $queries
1371-
* @param int|null $limit
1372-
* @param int|null $offset
1373-
* @param array<string> $orderAttributes
1374-
* @param array<string> $orderTypes
1375-
* @param array<string, mixed> $cursor
1376-
* @param string $cursorDirection
1377-
* @param string $forPermission
1378-
* @return array<Document>
1379-
* @throws DatabaseException
1380-
* @throws TimeoutException
1381-
* @throws Exception
1382-
*/
1383-
public function find(Document $collection, array $queries = [], ?int $limit = 25, ?int $offset = null, array $orderAttributes = [], array $orderTypes = [], array $cursor = [], string $cursorDirection = Database::CURSOR_AFTER, string $forPermission = Database::PERMISSION_READ): array
1384-
{
1385-
$spatialAttributes = $this->getSpatialAttributes($collection);
1386-
$attributes = $collection->getAttribute('attributes', []);
1387-
1388-
$collection = $collection->getId();
1389-
$name = $this->filter($collection);
1390-
$roles = Authorization::getRoles();
1391-
$where = [];
1392-
$orders = [];
1393-
$alias = Query::DEFAULT_ALIAS;
1394-
$binds = [];
1395-
1396-
$queries = array_map(fn ($query) => clone $query, $queries);
1397-
1398-
$cursorWhere = [];
1399-
1400-
foreach ($orderAttributes as $i => $originalAttribute) {
1401-
$attribute = $this->getInternalKeyForAttribute($originalAttribute);
1402-
$attribute = $this->filter($attribute);
1403-
1404-
$orderType = $this->filter($orderTypes[$i] ?? Database::ORDER_ASC);
1405-
$direction = $orderType;
1406-
1407-
if ($cursorDirection === Database::CURSOR_BEFORE) {
1408-
$direction = ($direction === Database::ORDER_ASC)
1409-
? Database::ORDER_DESC
1410-
: Database::ORDER_ASC;
1411-
}
1412-
1413-
$orders[] = "{$this->quote($attribute)} {$direction}";
1414-
1415-
// Build pagination WHERE clause only if we have a cursor
1416-
if (!empty($cursor)) {
1417-
// Special case: No tie breaks. only 1 attribute and it's a unique primary key
1418-
if (count($orderAttributes) === 1 && $i === 0 && $originalAttribute === '$sequence') {
1419-
$operator = ($direction === Database::ORDER_DESC)
1420-
? Query::TYPE_LESSER
1421-
: Query::TYPE_GREATER;
1422-
1423-
$bindName = ":cursor_pk";
1424-
$binds[$bindName] = $cursor[$originalAttribute];
1425-
1426-
$cursorWhere[] = "{$this->quote($alias)}.{$this->quote($attribute)} {$this->getSQLOperator($operator)} {$bindName}";
1427-
break;
1428-
}
1429-
1430-
$conditions = [];
1431-
1432-
// Add equality conditions for previous attributes
1433-
for ($j = 0; $j < $i; $j++) {
1434-
$prevOriginal = $orderAttributes[$j];
1435-
$prevAttr = $this->filter($this->getInternalKeyForAttribute($prevOriginal));
1436-
1437-
$bindName = ":cursor_{$j}";
1438-
$binds[$bindName] = $cursor[$prevOriginal];
1439-
1440-
$conditions[] = "{$this->quote($alias)}.{$this->quote($prevAttr)} = {$bindName}";
1441-
}
1442-
1443-
// Add comparison for current attribute
1444-
$operator = ($direction === Database::ORDER_DESC)
1445-
? Query::TYPE_LESSER
1446-
: Query::TYPE_GREATER;
1447-
1448-
$bindName = ":cursor_{$i}";
1449-
$binds[$bindName] = $cursor[$originalAttribute];
1450-
1451-
$conditions[] = "{$this->quote($alias)}.{$this->quote($attribute)} {$this->getSQLOperator($operator)} {$bindName}";
1452-
1453-
$cursorWhere[] = '(' . implode(' AND ', $conditions) . ')';
1454-
}
1455-
}
1456-
1457-
if (!empty($cursorWhere)) {
1458-
$where[] = '(' . implode(' OR ', $cursorWhere) . ')';
1459-
}
1460-
1461-
$conditions = $this->getSQLConditions($queries, $binds, attributes:$attributes);
1462-
if (!empty($conditions)) {
1463-
$where[] = $conditions;
1464-
}
1465-
1466-
if (Authorization::$status) {
1467-
$where[] = $this->getSQLPermissionsCondition($name, $roles, $alias, $forPermission);
1468-
}
1469-
1470-
if ($this->sharedTables) {
1471-
$binds[':_tenant'] = $this->tenant;
1472-
$where[] = "{$this->getTenantQuery($collection, $alias, condition: '')}";
1473-
}
1474-
1475-
$sqlWhere = !empty($where) ? 'WHERE ' . implode(' AND ', $where) : '';
1476-
$sqlOrder = 'ORDER BY ' . implode(', ', $orders);
1477-
1478-
$sqlLimit = '';
1479-
if (! \is_null($limit)) {
1480-
$binds[':limit'] = $limit;
1481-
$sqlLimit = 'LIMIT :limit';
1482-
}
1483-
1484-
if (! \is_null($offset)) {
1485-
$binds[':offset'] = $offset;
1486-
$sqlLimit .= ' OFFSET :offset';
1487-
}
1488-
1489-
$selections = $this->getAttributeSelections($queries);
1490-
1491-
1492-
$sql = "
1493-
SELECT {$this->getAttributeProjection($selections, $alias, $spatialAttributes)}
1494-
FROM {$this->getSQLTable($name)} AS {$this->quote($alias)}
1495-
{$sqlWhere}
1496-
{$sqlOrder}
1497-
{$sqlLimit};
1498-
";
1499-
1500-
$sql = $this->trigger(Database::EVENT_DOCUMENT_FIND, $sql);
1501-
1502-
try {
1503-
$stmt = $this->getPDO()->prepare($sql);
1504-
1505-
foreach ($binds as $key => $value) {
1506-
if (gettype($value) === 'double') {
1507-
$stmt->bindValue($key, $this->getFloatPrecision($value), PDO::PARAM_STR);
1508-
} else {
1509-
$stmt->bindValue($key, $value, $this->getPDOType($value));
1510-
}
1511-
}
1512-
1513-
$stmt->execute();
1514-
} catch (PDOException $e) {
1515-
throw $this->processException($e);
1516-
}
1517-
1518-
$results = $stmt->fetchAll();
1519-
$stmt->closeCursor();
1520-
1521-
foreach ($results as $index => $document) {
1522-
if (\array_key_exists('_uid', $document)) {
1523-
$results[$index]['$id'] = $document['_uid'];
1524-
unset($results[$index]['_uid']);
1525-
}
1526-
if (\array_key_exists('_id', $document)) {
1527-
$results[$index]['$sequence'] = $document['_id'];
1528-
unset($results[$index]['_id']);
1529-
}
1530-
if (\array_key_exists('_tenant', $document)) {
1531-
$results[$index]['$tenant'] = $document['_tenant'];
1532-
unset($results[$index]['_tenant']);
1533-
}
1534-
if (\array_key_exists('_createdAt', $document)) {
1535-
$results[$index]['$createdAt'] = $document['_createdAt'];
1536-
unset($results[$index]['_createdAt']);
1537-
}
1538-
if (\array_key_exists('_updatedAt', $document)) {
1539-
$results[$index]['$updatedAt'] = $document['_updatedAt'];
1540-
unset($results[$index]['_updatedAt']);
1541-
}
1542-
if (\array_key_exists('_createdBy', $document)) {
1543-
$results[$index]['$createdBy'] = $document['_createdBy'];
1544-
unset($results[$index]['_createdBy']);
1545-
}
1546-
if (\array_key_exists('_updatedBy', $document)) {
1547-
$results[$index]['$updatedBy'] = $document['_updatedBy'];
1548-
unset($results[$index]['_updatedBy']);
1549-
}
1550-
if (\array_key_exists('_permissions', $document)) {
1551-
$results[$index]['$permissions'] = \json_decode($document['_permissions'] ?? '[]', true);
1552-
unset($results[$index]['_permissions']);
1553-
}
1554-
1555-
$results[$index] = new Document($results[$index]);
1556-
}
1557-
1558-
if ($cursorDirection === Database::CURSOR_BEFORE) {
1559-
$results = \array_reverse($results);
1560-
}
1561-
1562-
return $results;
1563-
}
1564-
1565-
/**
1566-
* Count Documents
1567-
*
1568-
* @param Document $collection
1569-
* @param array<Query> $queries
1570-
* @param int|null $max
1571-
* @return int
1572-
* @throws Exception
1573-
* @throws PDOException
1574-
*/
1575-
public function count(Document $collection, array $queries = [], ?int $max = null): int
1576-
{
1577-
$attributes = $collection->getAttribute("attributes", []);
1578-
$collection = $collection->getId();
1579-
$name = $this->filter($collection);
1580-
$roles = Authorization::getRoles();
1581-
$binds = [];
1582-
$where = [];
1583-
$alias = Query::DEFAULT_ALIAS;
1584-
1585-
$limit = '';
1586-
if (! \is_null($max)) {
1587-
$binds[':limit'] = $max;
1588-
$limit = 'LIMIT :limit';
1589-
}
1590-
1591-
$queries = array_map(fn ($query) => clone $query, $queries);
1592-
1593-
$conditions = $this->getSQLConditions($queries, $binds, attributes:$attributes);
1594-
if (!empty($conditions)) {
1595-
$where[] = $conditions;
1596-
}
1597-
1598-
if (Authorization::$status) {
1599-
$where[] = $this->getSQLPermissionsCondition($name, $roles, $alias);
1600-
}
1601-
1602-
if ($this->sharedTables) {
1603-
$binds[':_tenant'] = $this->tenant;
1604-
$where[] = "{$this->getTenantQuery($collection, $alias, condition: '')}";
1605-
}
1606-
1607-
$sqlWhere = !empty($where)
1608-
? 'WHERE ' . \implode(' AND ', $where)
1609-
: '';
1610-
1611-
$sql = "
1612-
SELECT COUNT(1) as sum FROM (
1613-
SELECT 1
1614-
FROM {$this->getSQLTable($name)} AS {$this->quote($alias)}
1615-
{$sqlWhere}
1616-
{$limit}
1617-
) table_count
1618-
";
1619-
1620-
$sql = $this->trigger(Database::EVENT_DOCUMENT_COUNT, $sql);
1621-
1622-
$stmt = $this->getPDO()->prepare($sql);
1623-
1624-
foreach ($binds as $key => $value) {
1625-
$stmt->bindValue($key, $value, $this->getPDOType($value));
1626-
}
1627-
1628-
$stmt->execute();
1629-
1630-
$result = $stmt->fetchAll();
1631-
$stmt->closeCursor();
1632-
if (!empty($result)) {
1633-
$result = $result[0];
1634-
}
1635-
1636-
return $result['sum'] ?? 0;
1637-
}
1638-
1639-
/**
1640-
* Sum an Attribute
1641-
*
1642-
* @param Document $collection
1643-
* @param string $attribute
1644-
* @param array<Query> $queries
1645-
* @param int|null $max
1646-
* @return int|float
1647-
* @throws Exception
1648-
* @throws PDOException
1649-
*/
1650-
public function sum(Document $collection, string $attribute, array $queries = [], ?int $max = null): int|float
1651-
{
1652-
$collectionAttributes = $collection->getAttribute("attributes", []);
1653-
$collection = $collection->getId();
1654-
$name = $this->filter($collection);
1655-
$roles = Authorization::getRoles();
1656-
$where = [];
1657-
$alias = Query::DEFAULT_ALIAS;
1658-
$binds = [];
1659-
1660-
$limit = '';
1661-
if (! \is_null($max)) {
1662-
$binds[':limit'] = $max;
1663-
$limit = 'LIMIT :limit';
1664-
}
1665-
1666-
$queries = array_map(fn ($query) => clone $query, $queries);
1667-
1668-
$conditions = $this->getSQLConditions($queries, $binds, attributes:$collectionAttributes);
1669-
if (!empty($conditions)) {
1670-
$where[] = $conditions;
1671-
}
1672-
1673-
if (Authorization::$status) {
1674-
$where[] = $this->getSQLPermissionsCondition($name, $roles, $alias);
1675-
}
1676-
1677-
if ($this->sharedTables) {
1678-
$binds[':_tenant'] = $this->tenant;
1679-
$where[] = "{$this->getTenantQuery($collection, $alias, condition: '')}";
1680-
}
1681-
1682-
$sqlWhere = !empty($where)
1683-
? 'WHERE ' . \implode(' AND ', $where)
1684-
: '';
1685-
1686-
$sql = "
1687-
SELECT SUM({$this->quote($attribute)}) as sum FROM (
1688-
SELECT {$this->quote($attribute)}
1689-
FROM {$this->getSQLTable($name)} AS {$this->quote($alias)}
1690-
{$sqlWhere}
1691-
{$limit}
1692-
) table_count
1693-
";
1694-
1695-
$sql = $this->trigger(Database::EVENT_DOCUMENT_SUM, $sql);
1696-
1697-
$stmt = $this->getPDO()->prepare($sql);
1698-
1699-
foreach ($binds as $key => $value) {
1700-
$stmt->bindValue($key, $value, $this->getPDOType($value));
1701-
}
1702-
1703-
$stmt->execute();
1704-
1705-
$result = $stmt->fetchAll();
1706-
$stmt->closeCursor();
1707-
if (!empty($result)) {
1708-
$result = $result[0];
1709-
}
1710-
1711-
return $result['sum'] ?? 0;
1712-
}
1713-
17141364
/**
17151365
* Handle spatial queries
17161366
*
@@ -1991,9 +1641,9 @@ protected function getSQLType(string $type, int $size, bool $signed = true, bool
19911641
protected function getPDOType(mixed $value): int
19921642
{
19931643
return match (gettype($value)) {
1994-
'string','double' => PDO::PARAM_STR,
1995-
'integer', 'boolean' => PDO::PARAM_INT,
1996-
'NULL' => PDO::PARAM_NULL,
1644+
'string','double' => \PDO::PARAM_STR,
1645+
'integer', 'boolean' => \PDO::PARAM_INT,
1646+
'NULL' => \PDO::PARAM_NULL,
19971647
default => throw new DatabaseException('Unknown PDO Type for ' . \gettype($value)),
19981648
};
19991649
}

0 commit comments

Comments
 (0)