Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,20 @@ await test('createApp', async (t) => {
assert.deepEqual(data, { error: 'Body must be a JSON object' })
})

await t.test('GET /businesses?categories.id=... filters on array fields', async () => {
const business1 = { id: '1', categories: [{ id: 1 }, { id: 2 }] }
const business2 = { id: '2', categories: [{ id: 3 }] }
db.data = { businesses: [business1, business2] }

const matching = await fetch(`http://localhost:${port}/businesses?categories.id=2`)
assert.equal(matching.status, 200)
assert.deepEqual(await matching.json(), [business1])

const empty = await fetch(`http://localhost:${port}/businesses?categories.id=10`)
assert.equal(empty.status, 200)
assert.deepEqual(await empty.json(), [])
})

await t.test('PUT /posts/1 with null body returns 400', async () => {
const response = await fetch(`http://localhost:${port}/posts/1`, {
method: 'PUT',
Expand Down
27 changes: 26 additions & 1 deletion src/matches-where.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@ import type { JsonObject } from 'type-fest'
import { matchesWhere } from './matches-where.ts'

await test('matchesWhere', async (t) => {
const obj: JsonObject = { a: 10, b: 20, c: 'x', nested: { a: 10, b: 20 } }
const obj: JsonObject = {
a: 10,
b: 20,
c: 'x',
nested: { a: 10, b: 20 },
items: [
{ id: 1, name: 'foo' },
{ id: 2, name: 'bar' },
],
tags: ['red', 'blue'],
}
const cases: [JsonObject, boolean][] = [
[{ a: { eq: 10 } }, true],
[{ a: { eq: 11 } }, false],
Expand Down Expand Up @@ -53,6 +63,21 @@ await test('matchesWhere', async (t) => {
[{ c: { endsWith: 'z' } }, false],
[{ a: { endsWith: '1' } }, false],
[{ c: { endsWith: 1 } }, false],
// Array fields match when at least one item matches
[{ items: { id: { eq: 1 } } }, true],
[{ items: { id: { eq: 2 } } }, true],
[{ items: { id: { eq: 10 } } }, false],
[{ items: { id: { gt: 1 } } }, true],
[{ items: { id: { gt: 2 } } }, false],
[{ items: { name: { contains: 'BA' } } }, true],
[{ items: { name: { contains: 'baz' } } }, false],
// All conditions must be met by the same item
[{ items: { id: { eq: 1 }, name: { eq: 'foo' } } }, true],
[{ items: { id: { eq: 1 }, name: { eq: 'bar' } } }, false],
// Arrays of primitives have no properties to match
[{ tags: { id: { eq: 1 } } }, false],
[{ or: [{ items: { id: { eq: 10 } } }, { a: { eq: 10 } }] }, true],
[{ or: [{ items: { id: { eq: 10 } } }, { a: { eq: 11 } }] }, false],
]

for (const [query, expected] of cases) {
Expand Down
7 changes: 7 additions & 0 deletions src/matches-where.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ export function matchesWhere(obj: JsonObject, where: JsonObject): boolean {
continue
}

// An array matches if at least one of its items matches
if (Array.isArray(field)) {
const matched = field.some((item) => isJSONObject(item) && matchesWhere(item, value))
if (!matched) return false
continue
}

if (isJSONObject(field)) {
if (!matchesWhere(field, value)) return false
}
Expand Down