Skip to content

Commit 189f80b

Browse files
committed
Fix computation of joins inside nested objects
1 parent 7c31bb5 commit 189f80b

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
@@ -75,18 +75,27 @@ private function __construct(array $schema, array $request_params)
7575

7676
private function getSQLFieldForProperty(string $prop_name): string
7777
{
78-
$prop = $this->flattened_properties[$prop_name];
79-
$is_join = str_contains($prop_name, '.');
80-
$sql_field = $prop['x-field'] ?? $prop_name;
78+
$real_prop_name = str_replace(chr(0x1F), '.', $prop_name);
79+
$prop = $this->flattened_properties[$real_prop_name];
80+
$is_join = str_contains($real_prop_name, '.');
81+
$sql_field = $prop['x-field'] ?? $real_prop_name;
8182
if (!$is_join) {
8283
// Only add the _. prefix if it isn't a join
8384
$sql_field = "_.$sql_field";
84-
} else if ($prop_name !== $sql_field) {
85+
} else if ($real_prop_name !== $sql_field) {
8586
// If the property name is different from the SQL field name, we will need to add/change the table alias
8687
// $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
87-
$join_alias = explode('.', $prop_name)[0];
88+
$parts = explode('.', $prop_name);
89+
array_pop($parts); // Get rid of the field
90+
$join_alias = implode('.', $parts);
8891
$sql_field = "{$join_alias}.{$sql_field}";
8992
}
93+
$parts = explode('.', $sql_field);
94+
if (count($parts) > 2) {
95+
$field = array_pop($parts);
96+
$table = implode(chr(0x1F), $parts);
97+
$sql_field = "{$table}.{$field}";
98+
}
9099
return $sql_field;
91100
}
92101

@@ -98,6 +107,7 @@ private function getSelectCriteriaForProperty(string $prop_name, bool $distinct_
98107
{
99108
global $DB;
100109

110+
$prop_name = str_replace(chr(0x1F), '.', $prop_name);
101111
$prop = $this->flattened_properties[$prop_name];
102112
if ($prop['x-writeonly'] ?? false) {
103113
// Do not expose write-only fields
@@ -157,6 +167,7 @@ private static function getJoins(string $join_alias, array $join_definition): ar
157167
if (!isset($joins[$join_type])) {
158168
$joins[$join_type] = [];
159169
}
170+
$join_alias = str_replace('.', chr(0x1F), $join_alias);
160171
$join_table = $join['table'] . ' AS ' . $join_alias;
161172
$join_parent = (isset($join['ref_join']) && $join['ref_join']) ? "{$join_alias}_ref" : '_';
162173
if (isset($join['ref_join'])) {
@@ -304,6 +315,7 @@ private function getMatchingRecords($ignore_pagination = false): array
304315
$criteria['GROUPBY'] = ['_itemtype', '_.id'];
305316
} else {
306317
foreach ($this->joins as $join_alias => $join) {
318+
$join_alias = str_replace('.', chr(0x1F), $join_alias);
307319
$s = $this->getSelectCriteriaForProperty("$join_alias.id", true);
308320
if ($s !== null) {
309321
$criteria['SELECT'][] = $s;
@@ -409,6 +421,11 @@ private function hydrateRecords(array $records): array
409421
}
410422
} else {
411423
foreach ($this->joins as $join_alias => $join) {
424+
$parts = explode(chr(0x1F), $fkey);
425+
if (count($parts) > 1) {
426+
$field = array_pop($parts);
427+
$fkey = implode('.', $parts) . chr(0x1F) . $field;
428+
}
412429
if ($fkey === $join_alias . chr(0x1F) . 'id') {
413430
$fkey_tables[$fkey] = $join['table'];
414431
break;
@@ -454,17 +471,20 @@ private function hydrateRecords(array $records): array
454471
$criteria['SELECT'][] = new QueryExpression($DB::quoteValue($schema_name), '_itemtype');
455472
}
456473
} else {
457-
$join_name = explode(chr(0x1F), $fkey)[0];
458-
$props_to_use = array_filter($this->flattened_properties, static function ($prop_name) use ($join_name) {
459-
return str_starts_with($prop_name, $join_name . '.');
474+
$join_name_parts = explode(chr(0x1F), $fkey);
475+
array_pop($join_name_parts);
476+
$join_name = implode(chr(0x1F), $join_name_parts);
477+
$join_name_dotted = str_replace(chr(0x1F), '.', $join_name);
478+
$props_to_use = array_filter($this->flattened_properties, static function ($prop_name) use ($join_name_dotted) {
479+
return str_starts_with($prop_name, $join_name_dotted . '.');
460480
}, ARRAY_FILTER_USE_KEY);
461481

462482
$criteria['FROM'] = "$table AS " . $DB::quoteName($join_name);
463483
$id_field = $join_name . '.id';
464484
}
465485
$criteria['WHERE'] = [$id_field => $ids_to_fetch];
466486
foreach ($props_to_use as $prop_name => $prop) {
467-
if ($prop['x-writeonly'] ?? false) {
487+
if ($prop['x-writeonly'] ?? false || isset($prop['x-mapped-from'])) {
468488
continue;
469489
}
470490
$criteria['SELECT'][] = $this->getSQLFieldForProperty($prop_name) . ' AS ' . str_replace('.', chr(0x1F), $prop_name);

0 commit comments

Comments
 (0)