Skip to content

Commit 5f61be5

Browse files
committed
Add eq filter support
1 parent 594d845 commit 5f61be5

File tree

3 files changed

+92
-2
lines changed

3 files changed

+92
-2
lines changed

packages/host/tests/unit/query-test.ts

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { module, test } from 'qunit';
1+
import { module, test, skip } from 'qunit';
22

33
import {
44
Loader,
@@ -118,4 +118,34 @@ module('Unit | query', function (hooks) {
118118
'results are correct',
119119
);
120120
});
121+
122+
test(`can filter using 'eq'`, async function (assert) {
123+
let { mango, vangogh, paper } = testCards;
124+
await setupIndex(client, [
125+
{ card: mango, data: { search_doc: { name: 'Mango' } } },
126+
{ card: vangogh, data: { search_doc: { name: 'Van Gogh' } } },
127+
// this card's "name" field doesn't match our filter since our filter
128+
// specified "name" fields of Person cards
129+
{ card: paper, data: { search_doc: { name: 'Mango' } } },
130+
]);
131+
132+
let { cards, meta } = await client.search(
133+
{
134+
filter: {
135+
eq: { name: 'Mango' },
136+
on: { module: `${testRealmURL}person`, name: 'Person' },
137+
},
138+
},
139+
loader,
140+
);
141+
142+
assert.strictEqual(meta.page.total, 1, 'the total results meta is correct');
143+
assert.deepEqual(
144+
cards,
145+
[await serializeCard(mango)],
146+
'results are correct',
147+
);
148+
});
149+
150+
skip(`can filter using 'eq' thru nested fields`);
121151
});

packages/runtime-common/indexer/client.ts

+34-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as JSONTypes from 'json-typescript';
12
import flatten from 'lodash/flatten';
23
import {
34
type LooseCardResource,
@@ -22,8 +23,10 @@ import {
2223
addExplicitParens,
2324
asExpressions,
2425
every,
26+
fieldQuery,
27+
fieldValue,
2528
} from './expression';
26-
import { type Query, type Filter } from '../query';
29+
import { type Query, type Filter, type EqFilter } from '../query';
2730
import { type SerializedError } from '../error';
2831
import { type DBAdapter } from '../db';
2932
import { type SearchEntryWithErrors } from '../search-index';
@@ -249,6 +252,10 @@ export class IndexerDBClient {
249252

250253
// TODO: any, every, not, eq, contains, range
251254

255+
if ('eq' in filter) {
256+
return this.eqCondition(filter, on);
257+
}
258+
252259
throw new Error(`Unknown filter: ${JSON.stringify(filter)}`);
253260
}
254261

@@ -262,6 +269,32 @@ export class IndexerDBClient {
262269
];
263270
}
264271

272+
private eqCondition(filter: EqFilter, on: CodeRef): CardExpression {
273+
on = filter.on ?? on;
274+
return every([
275+
this.typeCondition(on),
276+
...Object.entries(filter.eq).map(([key, value]) => {
277+
return this.fieldFilter(key, value, on);
278+
}),
279+
]);
280+
}
281+
282+
// TODO handle containsMany fields. Take a look at how FieldArity works in hub
283+
// v2 for an example which let's us use a different card expression for
284+
// singular fields vs plural fields. Also plural fields will really push
285+
// SQLite to the extreme in terms of the query that we need--this is
286+
// challenging because the original hub v2 implementation leveraged array
287+
// operators for this query which SQLite does not have.
288+
private fieldFilter(
289+
key: string,
290+
value: JSONTypes.Value,
291+
onRef: CodeRef,
292+
): CardExpression {
293+
let query = fieldQuery(key, onRef, 'filter');
294+
let v = fieldValue(key, [param(value)], onRef, 'filter');
295+
return [query, '=', v];
296+
}
297+
265298
private async cardQueryToSQL(query: CardExpression, loader: Loader) {
266299
return this.expressionToSql(await this.makeExpression(query, loader));
267300
}

packages/runtime-common/indexer/expression.ts

+27
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,33 @@ export function tableValuedFunction(
9393
};
9494
}
9595

96+
export function fieldQuery(
97+
path: string,
98+
type: CodeRef,
99+
errorHint: string,
100+
): FieldQuery {
101+
return {
102+
type,
103+
path,
104+
errorHint,
105+
kind: 'field-query',
106+
};
107+
}
108+
109+
export function fieldValue(
110+
path: string,
111+
value: CardExpression,
112+
type: CodeRef,
113+
errorHint: string,
114+
): FieldValue {
115+
return {
116+
type,
117+
path,
118+
value,
119+
errorHint,
120+
kind: 'field-value',
121+
};
122+
}
96123
export function every(expressions: CardExpression[]): CardExpression;
97124
export function every(expressions: Expression[]): Expression;
98125
export function every(expressions: unknown[][]): unknown {

0 commit comments

Comments
 (0)