Skip to content

Commit 2e569f1

Browse files
os-zhuangclaude
andcommitted
fix(objectql): normalize OData $search/$searchFields so the search executor runs (ADR-0061)
Follow-up to the $search executor (#2134): over the REST/OData path the term never reached engine.find(). protocol.findData() normalizes $-prefixed OData params ($top/$skip/$orderby/$select/$count) to bare names, but NOT $search / $searchFields — so `$search=retail` fell through to the implicit-field-filter pass and became `where.$search = 'retail'` (a non-existent column), which the driver silently returns [] for. The engine's expandSearchToFilter (which reads ast.search) therefore never fired. - Add ['$search','search'] and ['$searchFields','searchFields'] to the dollar→bare normalization, and add 'searchFields' to knownParams so the bare form isn't treated as an implicit filter. - Test: findData normalizes $search/$searchFields to bare and never leaks them into where. Verified end-to-end over the real HTTP API against a dev backend: searching "retail" returns the 3 retail-industry accounts (matched by the industry label→value), "technology" → 4, "Contoso" → 1 by name, "zzqq" → 0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent d0fa753 commit 2e569f1

2 files changed

Lines changed: 15 additions & 1 deletion

File tree

packages/objectql/src/protocol-data.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ describe('ObjectStackProtocolImplementation - Data Operations', () => {
2525
// ═══════════════════════════════════════════════════════════════
2626

2727
describe('findData', () => {
28+
it('normalizes $search/$searchFields (OData) to bare search/searchFields, not implicit filters', async () => {
29+
await protocol.findData({ object: 'showcase_account', query: { $search: 'retail', $searchFields: ['name', 'industry'] } });
30+
const opts = mockEngine.find.mock.calls[0][1];
31+
expect(opts.search).toBe('retail');
32+
expect(opts.searchFields).toEqual(['name', 'industry']);
33+
expect(opts.$search).toBeUndefined();
34+
expect(opts.$searchFields).toBeUndefined();
35+
// critical: must NOT fall through to the implicit-filter pass as where.$search
36+
expect(opts.where?.$search).toBeUndefined();
37+
expect(opts.where?.searchFields).toBeUndefined();
38+
});
39+
2840
it('should normalize $expand (OData) string to expand Record', async () => {
2941
await protocol.findData({ object: 'order_item', query: { $expand: 'order,product' } });
3042

packages/objectql/src/protocol.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2021,6 +2021,8 @@ export class ObjectStackProtocolImplementation implements ObjectStackProtocol {
20212021
['$orderby', 'orderBy'],
20222022
['$select', 'select'],
20232023
['$count', 'count'],
2024+
['$search', 'search'],
2025+
['$searchFields', 'searchFields'],
20242026
] as const) {
20252027
if (options[dollar] != null && options[bare] == null) {
20262028
options[bare] = options[dollar];
@@ -2133,7 +2135,7 @@ export class ObjectStackProtocolImplementation implements ObjectStackProtocol {
21332135
'expand',
21342136
'distinct', 'count',
21352137
'aggregations', 'groupBy',
2136-
'search', 'context', 'cursor',
2138+
'search', 'searchFields', 'context', 'cursor',
21372139
]);
21382140
if (!options.where) {
21392141
const implicitFilters: Record<string, unknown> = {};

0 commit comments

Comments
 (0)