more copilot comments fixed

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2026-02-14 20:59:16 +01:00
parent aee4f26c88
commit 1e5464cdf0
4 changed files with 96 additions and 32 deletions
@@ -951,6 +951,27 @@ describe('DefaultLocationStore', () => {
items: [l1, l2, l3, l4],
totalItems: 4,
});
await expect(
store.queryLocations({ limit: 10, query: { $all: [] } }),
).resolves.toEqual({
items: [],
totalItems: 0,
});
await expect(
store.queryLocations({ limit: 10, query: { $any: [] } }),
).resolves.toEqual({
items: [],
totalItems: 0,
});
await expect(
store.queryLocations({ limit: 10, query: { type: { $in: [] } } }),
).resolves.toEqual({
items: [],
totalItems: 0,
});
},
);
});
@@ -109,7 +109,10 @@ export class DefaultLocationStore implements LocationStore, EntityProvider {
afterId?: string;
query?: FilterPredicate;
}): Promise<{ items: Location[]; totalItems: number }> {
let itemsQuery = this.db<DbLocationsRow>('locations');
let itemsQuery = this.db<DbLocationsRow>('locations').whereNot(
'type',
'bootstrap',
);
if (options.query) {
itemsQuery = applyLocationFilterToQuery(
@@ -558,6 +561,9 @@ function applyLocationFilterToQuery(
}
if ('$all' in query) {
if (query.$all.length === 0) {
return result.whereRaw('1 = 0');
}
return result.where(outer => {
for (const subQuery of query.$all) {
outer.andWhere(inner => {
@@ -568,6 +574,9 @@ function applyLocationFilterToQuery(
}
if ('$any' in query) {
if (query.$any.length === 0) {
return result.whereRaw('1 = 0');
}
return result.where(outer => {
for (const subQuery of query.$any) {
outer.orWhere(inner => {
@@ -636,46 +645,51 @@ function applyLocationFilterToQuery(
? result.whereNotNull(key)
: result.whereNull(key);
} else if ('$in' in value) {
if (key === 'id') {
if (value.$in.length === 0) {
result = result.whereRaw('1 = 0');
} else if (key === 'id') {
result = result.whereIn(key, value.$in);
} else if (clientType === 'pg') {
result = result.whereRaw(
`UPPER(??::text) IN (${value.$in
.map(() => 'UPPER(?::text)')
.join(', ')})`,
[key, ...value.$in],
);
const rhs = value.$in.map(() => 'UPPER(?::text)').join(', ');
result = result.whereRaw(`UPPER(??::text) IN (${rhs})`, [
key,
...value.$in,
]);
} else if (clientType.includes('mysql')) {
result = result.whereRaw(
`UPPER(CAST(?? AS CHAR)) IN (${value.$in
.map(() => 'UPPER(CAST(? AS CHAR))')
.join(', ')})`,
[key, ...value.$in],
);
const rhs = value.$in.map(() => 'UPPER(CAST(? AS CHAR))').join(', ');
result = result.whereRaw(`UPPER(CAST(?? AS CHAR)) IN (${rhs})`, [
key,
...value.$in,
]);
} else {
result = result.whereRaw(
`UPPER(??) IN (${value.$in.map(() => 'UPPER(?)').join(', ')})`,
[key, ...value.$in],
);
const rhs = value.$in.map(() => 'UPPER(?)').join(', ');
result = result.whereRaw(`UPPER(??) IN (${rhs})`, [
key,
...value.$in,
]);
}
} else if ('$hasPrefix' in value) {
const escaped = value.$hasPrefix.replace(/([\\%_])/g, '\\$1');
if (clientType === 'pg') {
result = result.whereRaw('?? ilike ?', [key, `${escaped}%`]);
result = result.whereRaw("?? ilike ? escape '\\'", [
key,
`${escaped}%`,
]);
} else if (clientType.includes('mysql')) {
result = result.whereRaw("UPPER(??) like UPPER(?) escape '\\\\'", [
key,
`${escaped}%`,
]);
} else {
result = result.whereRaw('UPPER(??) like UPPER(?)', [
result = result.whereRaw("UPPER(??) like UPPER(?) escape '\\'", [
key,
`${escaped}%`,
]);
}
} else if ('$contains' in value) {
// There are no array shaped values for location queries, so we throw
// an error since it cannot possibly match. An alternative could be to
// make the query always fail (eg with 1 = 0) but this felt more
// immediately helpful to the end user.
throw new InputError(
`Invalid filter predicate, '$contains' is not supported for location queries`,
);
// There are no array shaped values for location queries, so we just
// always fail here
result = result.whereRaw('1 = 0');
} else {
throw new InputError(
`Invalid filter predicate, got unknown matcher object '${JSON.stringify(
@@ -605,7 +605,7 @@ export async function createRouter(
});
try {
const request = parseLocationQuery(req.body);
const request = parseLocationQuery(req.body ?? {});
const result = await locationService.queryLocations({
...request,
limit: request.limit + 1,
@@ -32,6 +32,20 @@ const locationCursorParser = z.object({
query: filterPredicateSchema.optional(),
});
function isSupportedFilterPredicateRoot(
value: FilterPredicate | undefined,
): boolean {
if (value === undefined) {
return true;
}
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
return false;
}
return true;
}
export function parseLocationQuery(
request: Readonly<GetLocationsByQueryRequest>,
): {
@@ -39,7 +53,11 @@ export function parseLocationQuery(
afterId?: string;
query?: FilterPredicate;
} {
if (request.cursor) {
if (request.cursor !== undefined) {
if (!request.cursor) {
throw new InputError('Cursor cannot be empty');
}
let parsed: JsonValue;
try {
const data = Buffer.from(request.cursor, 'base64').toString('utf8');
@@ -52,10 +70,16 @@ export function parseLocationQuery(
if (!result.success) {
throw new InputError(`Malformed cursor: ${fromZodError(result.error)}`);
}
const { query, limit, afterId } = result.data;
if (!isSupportedFilterPredicateRoot(query)) {
throw new InputError('Query must be an object');
}
return {
limit: result.data.limit,
afterId: result.data.afterId,
query: result.data.query,
limit,
afterId,
query,
};
}
@@ -70,6 +94,11 @@ export function parseLocationQuery(
if (!result.success) {
throw new InputError(`Invalid query: ${fromZodError(result.error)}`);
}
if (!isSupportedFilterPredicateRoot(result.data)) {
throw new InputError('Query must be an object');
}
query = result.data;
}