Skip to content

Commit e85574c

Browse files
committed
Fix computation of joins inside nested objects
1 parent dd798bb commit e85574c

File tree

2 files changed

+31
-11
lines changed

2 files changed

+31
-11
lines changed

src/Api/HL/Doc/Schema.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,9 +213,9 @@ public static function getJoins(array $props, string $prefix = ''): array
213213
$joins = [];
214214
foreach ($props as $name => $prop) {
215215
if ($prop['type'] === self::TYPE_OBJECT && isset($prop['x-join'])) {
216-
$joins[$name] = $prop['x-join'] + ['parent_type' => self::TYPE_OBJECT];
216+
$joins[$prefix . $name] = $prop['x-join'] + ['parent_type' => self::TYPE_OBJECT];
217217
} else if ($prop['type'] === self::TYPE_ARRAY && isset($prop['items']['x-join'])) {
218-
$joins[$name] = $prop['items']['x-join'] + ['parent_type' => self::TYPE_ARRAY];
218+
$joins[$prefix . $name] = $prop['items']['x-join'] + ['parent_type' => self::TYPE_ARRAY];
219219
} else if ($prop['type'] === self::TYPE_OBJECT && isset($prop['properties'])) {
220220
$joins += self::getJoins($prop['properties'], $prefix . $name . '.');
221221
}

src/Api/HL/Search.php

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -82,18 +82,27 @@ private function __construct(array $schema, array $request_params)
8282

8383
private function getSQLFieldForProperty(string $prop_name): string
8484
{
85-
$prop = $this->flattened_properties[$prop_name];
86-
$is_join = str_contains($prop_name, '.') && array_key_exists(explode('.', $prop_name)[0], $this->joins);
87-
$sql_field = $prop['x-field'] ?? $prop_name;
85+
$real_prop_name = str_replace(chr(0x1F), '.', $prop_name);
86+
$prop = $this->flattened_properties[$real_prop_name];
87+
$is_join = str_contains($real_prop_name, '.') && array_key_exists(explode('.', $real_prop_name)[0], $this->joins);
88+
$sql_field = $prop['x-field'] ?? $real_prop_name;
8889
if (!$is_join) {
8990
// Only add the _. prefix if it isn't a join
9091
$sql_field = "_.$sql_field";
91-
} else if ($prop_name !== $sql_field) {
92+
} else if ($real_prop_name !== $sql_field) {
9293
// If the property name is different from the SQL field name, we will need to add/change the table alias
9394
// $prop_name is a join where the part before the dot is the join alias (also the property on the main item), and the part after the dot is the property on the joined item
94-
$join_alias = explode('.', $prop_name)[0];
95+
$parts = explode('.', $prop_name);
96+
array_pop($parts); // Get rid of the field
97+
$join_alias = implode('.', $parts);
9598
$sql_field = "{$join_alias}.{$sql_field}";
9699
}
100+
$parts = explode('.', $sql_field);
101+
if (count($parts) > 2) {
102+
$field = array_pop($parts);
103+
$table = implode(chr(0x1F), $parts);
104+
$sql_field = "{$table}.{$field}";
105+
}
97106
return $sql_field;
98107
}
99108

@@ -105,6 +114,7 @@ private function getSelectCriteriaForProperty(string $prop_name, bool $distinct_
105114
{
106115
global $DB;
107116

117+
$prop_name = str_replace(chr(0x1F), '.', $prop_name);
108118
$prop = $this->flattened_properties[$prop_name];
109119
if ($prop['x-writeonly'] ?? false) {
110120
// Do not expose write-only fields
@@ -164,6 +174,7 @@ private static function getJoins(string $join_alias, array $join_definition): ar
164174
if (!isset($joins[$join_type])) {
165175
$joins[$join_type] = [];
166176
}
177+
$join_alias = str_replace('.', chr(0x1F), $join_alias);
167178
$join_table = $join['table'] . ' AS ' . $join_alias;
168179
$join_parent = (isset($join['ref_join']) && $join['ref_join']) ? "{$join_alias}_ref" : '_';
169180
if (isset($join['ref_join'])) {
@@ -390,6 +401,7 @@ private function getMatchingRecords($ignore_pagination = false): array
390401
$criteria['GROUPBY'] = ['_itemtype', '_.id'];
391402
} else {
392403
foreach ($this->joins as $join_alias => $join) {
404+
$join_alias = str_replace('.', chr(0x1F), $join_alias);
393405
$s = $this->getSelectCriteriaForProperty("$join_alias.id", true);
394406
if ($s !== null) {
395407
$criteria['SELECT'][] = $s;
@@ -495,6 +507,11 @@ private function hydrateRecords(array $records): array
495507
}
496508
} else {
497509
foreach ($this->joins as $join_alias => $join) {
510+
$parts = explode(chr(0x1F), $fkey);
511+
if (count($parts) > 1) {
512+
$field = array_pop($parts);
513+
$fkey = implode('.', $parts) . chr(0x1F) . $field;
514+
}
498515
if ($fkey === $join_alias . chr(0x1F) . 'id') {
499516
$fkey_tables[$fkey] = $join['table'];
500517
break;
@@ -543,17 +560,20 @@ private function hydrateRecords(array $records): array
543560
$criteria['SELECT'][] = new QueryExpression($DB::quoteValue($schema_name), '_itemtype');
544561
}
545562
} else {
546-
$join_name = explode(chr(0x1F), $fkey)[0];
547-
$props_to_use = array_filter($this->flattened_properties, static function ($prop_name) use ($join_name) {
548-
return str_starts_with($prop_name, $join_name . '.');
563+
$join_name_parts = explode(chr(0x1F), $fkey);
564+
array_pop($join_name_parts);
565+
$join_name = implode(chr(0x1F), $join_name_parts);
566+
$join_name_dotted = str_replace(chr(0x1F), '.', $join_name);
567+
$props_to_use = array_filter($this->flattened_properties, static function ($prop_name) use ($join_name_dotted) {
568+
return str_starts_with($prop_name, $join_name_dotted . '.');
549569
}, ARRAY_FILTER_USE_KEY);
550570

551571
$criteria['FROM'] = "$table AS " . $DB::quoteName($join_name);
552572
$id_field = $join_name . '.id';
553573
}
554574
$criteria['WHERE'] = [$id_field => $ids_to_fetch];
555575
foreach ($props_to_use as $prop_name => $prop) {
556-
if ($prop['x-writeonly'] ?? false) {
576+
if ($prop['x-writeonly'] ?? false || isset($prop['x-mapped-from'])) {
557577
continue;
558578
}
559579
$sql_field = $this->getSQLFieldForProperty($prop_name);

0 commit comments

Comments
 (0)