|
1 | 1 | import { describe, expect, it } from 'bun:test' |
2 | 2 |
|
| 3 | +import { LibSQLDatabase } from 'drizzle-orm/libsql' |
| 4 | +import { SQLiteRelationalQuery } from 'drizzle-orm/sqlite-core/query-builders/query' |
3 | 5 | import { parse } from 'smol-toml' |
4 | 6 |
|
5 | 7 | import { LineGroups } from '#collections-types/line-groups' |
6 | 8 |
|
7 | 9 | import createDbClient from '.' |
| 10 | +import { getQueryPlan } from './query-utils' |
| 11 | +import relations from './relations' |
| 12 | +import * as schema from './schema' |
8 | 13 |
|
9 | 14 | const getCollectionDoc = async <Schema>(document: string) => |
10 | 15 | parse(await Bun.file(`collections/${document}.toml`).text()) as Schema |
11 | 16 |
|
| 17 | +// Generic function to test query plan optimization |
| 18 | +const expectOptimizedQueryPlan = async <Q extends SQLiteRelationalQuery<'async', unknown>>( |
| 19 | + db: LibSQLDatabase<typeof schema, typeof relations>, |
| 20 | + query: Q, |
| 21 | + { |
| 22 | + maxTableScans = 0, |
| 23 | + expectedIndexes = [], |
| 24 | + }: { maxTableScans?: number; expectedIndexes?: string[] } = {}, |
| 25 | +) => { |
| 26 | + const queryPlan = await getQueryPlan(db, query) |
| 27 | + const planText = queryPlan.join(' ') |
| 28 | + |
| 29 | + const tableScans = queryPlan.filter( |
| 30 | + (step) => typeof step === 'string' && step.includes('SCAN') && !step.includes('USING INDEX'), |
| 31 | + ).length |
| 32 | + |
| 33 | + expect(tableScans, planText).toBeLessThanOrEqual(maxTableScans) |
| 34 | + expectedIndexes.forEach((indexName) => expect(planText).toContain(indexName)) |
| 35 | + |
| 36 | + return queryPlan |
| 37 | +} |
| 38 | + |
12 | 39 | describe('Database', () => { |
13 | | - it('should return lines in order', async () => { |
14 | | - const db = createDbClient() |
15 | | - const id = 'DMP' |
16 | | - |
17 | | - const lineGroup = await db.query.lineGroups.findFirst({ |
18 | | - where: { id }, |
19 | | - with: { |
20 | | - author: true, |
21 | | - lines: { |
22 | | - orderBy: { |
23 | | - lineGroupOrder: 'asc', |
| 40 | + describe('line groups', () => { |
| 41 | + it('should return, optimized, lines in order', async () => { |
| 42 | + const db = createDbClient() |
| 43 | + const id = 'DMP' |
| 44 | + |
| 45 | + const lineGroupQuery = db.query.lineGroups.findFirst({ |
| 46 | + where: { id }, |
| 47 | + with: { |
| 48 | + author: true, |
| 49 | + lines: { |
| 50 | + orderBy: { |
| 51 | + lineGroupOrder: 'asc', |
| 52 | + }, |
24 | 53 | }, |
25 | 54 | }, |
26 | | - }, |
27 | | - }) |
| 55 | + }) |
| 56 | + const lineGroup = await lineGroupQuery |
28 | 57 |
|
29 | | - const collectionDoc = await getCollectionDoc<LineGroups>(`line-groups/D/${id}`) |
30 | | - expect(lineGroup?.lines.map((line) => line.id)).toEqual(collectionDoc.lines) |
31 | | - expect(lineGroup?.author.id).toEqual(collectionDoc.author) |
| 58 | + const collectionDoc = await getCollectionDoc<LineGroups>(`line-groups/D/${id}`) |
| 59 | + |
| 60 | + expect(lineGroup?.lines.map((line) => line.id)).toEqual(collectionDoc.lines) |
| 61 | + expect(lineGroup?.author.id).toEqual(collectionDoc.author) |
| 62 | + await expectOptimizedQueryPlan(db, lineGroupQuery, { |
| 63 | + maxTableScans: 2, |
| 64 | + expectedIndexes: [ |
| 65 | + 'sqlite_autoindex_line_groups_1', |
| 66 | + 'sqlite_autoindex_authors_1', |
| 67 | + 'line_group_id_order_index', |
| 68 | + ], |
| 69 | + }) |
| 70 | + }) |
32 | 71 | }) |
33 | 72 | }) |
0 commit comments