Skip to content

Commit

Permalink
Fix PUT/PATCH/DELETE requests when translations of the ID field are used
Browse files Browse the repository at this point in the history
Change-type: patch
  • Loading branch information
thgreasi committed Aug 26, 2024
1 parent 522ae49 commit 75c4cec
Showing 1 changed file with 71 additions and 1 deletion.
72 changes: 71 additions & 1 deletion src/odata-to-abstract-sql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import stringHash = require('string-hash');
import {
isAliasNode,
isFromNode,
isSelectNode,
isSelectQueryNode,
isTableNode,
} from '@balena/abstract-sql-compiler';
import type {
Expand Down Expand Up @@ -69,6 +71,7 @@ import type {
IsNotDistinctFromNode,
IsDistinctFromNode,
UnknownTypeNodes,
FromTypeNode,
} from '@balena/abstract-sql-compiler';
import type {
ODataBinds,
Expand Down Expand Up @@ -176,6 +179,58 @@ const containsQueryOption = (opts?: object): boolean => {
return false;
};

const addNestedFieldSelect = (
selectNode: SelectNode[1],
fromNode: FromNode[1],
fieldName: string,
fieldNameAlias: string,
) => {
let aliasName: string | undefined;
let tableOrSubqueryNode: FromTypeNode[keyof FromTypeNode];
if (isAliasNode(fromNode)) {
tableOrSubqueryNode = fromNode[1];
aliasName = fromNode[2];
} else {
tableOrSubqueryNode = fromNode;
if (!isTableNode(tableOrSubqueryNode)) {
throw new Error('');
}
}
if (isTableNode(tableOrSubqueryNode)) {
selectNode.push([
'Alias',
['ReferencedField', aliasName ?? tableOrSubqueryNode[1], fieldName],
fieldNameAlias,
]);
return;
}
if (!isSelectQueryNode(tableOrSubqueryNode)) {
throw new Error(
`Adding a nested field select to a subquery containing a ${tableOrSubqueryNode[0]} is not supported`,
);
}
if (aliasName == null) {
// This should never happen but we are checking it to make TS happy.
throw new Error('Found unaliased SelectQueryNode');
}
const nestedSelectNode = tableOrSubqueryNode.find(isSelectNode);
if (nestedSelectNode == null) {
throw new Error(`Cannot find SelectNode in subquery`);
}
const nestedFromNode = tableOrSubqueryNode.find(isFromNode);
if (nestedFromNode == null) {
throw new Error(`Cannot find FromNode in subquery`);
}
addNestedFieldSelect(
nestedSelectNode[1],
nestedFromNode[1],
fieldName,
fieldNameAlias,
);
selectNode.push(['ReferencedField', aliasName, fieldNameAlias]);
return;
};

class Query {
public select: Array<
| ReferencedFieldNode
Expand Down Expand Up @@ -215,6 +270,14 @@ class Query {
);
this.from.push(tableRef);
}
addNestedFieldSelect(fieldName: string, fieldNameAlias: string): void {
if (this.from.length !== 1) {
throw new Error(
`Adding nested field SELECTs is only supported for queries with exactly 1 FROM clause. Found ${this.from.length}`,
);
}
addNestedFieldSelect(this.select, this.from[0], fieldName, fieldNameAlias);
}
compile(queryType: 'SelectQuery'): SelectQueryNode;
compile(queryType: 'InsertQuery'): InsertQueryNode;
compile(queryType: 'UpdateQuery'): UpdateQueryNode;
Expand Down Expand Up @@ -717,8 +780,15 @@ export class OData2AbstractSQL {
) {
// For update/delete statements we need to use a style query
const subQuery = new Query();
subQuery.select.push(referencedIdField);
subQuery.fromResource(this, resource);
subQuery.addNestedFieldSelect(
resource.idField,
method === 'PATCH'
? '$updateid'
: method === 'DELETE'
? '$deleteid'
: '$upsertid',
);
if (hasQueryOpts) {
this.AddQueryOptions(resource, path, subQuery);
}
Expand Down

0 comments on commit 75c4cec

Please sign in to comment.