1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
import { describe, it, expect, beforeEach } from 'vitest';
import { groceries, references } from '$lib/server/db/schema';
import { eq } from 'drizzle-orm';
import { createTestDb, type TestDb } from '$lib/server/db/test-helper';
import { ReferencesService } from './references';
describe('references service', () => {
let db: TestDb['db'];
let service: ReferencesService;
beforeEach(async () => {
db = (await createTestDb()).db;
service = new ReferencesService(db);
});
it('loadForGrocery returns refs for the given grocery', async () => {
const now = Temporal.Now.instant().toString({
smallestUnit: 'millisecond',
});
const [g1] = await db
.insert(groceries)
.values({ name: 'coffee', checked: false, createdAt: now })
.returning();
const [g2] = await db
.insert(groceries)
.values({ name: 'tea', checked: false, createdAt: now })
.returning();
await db.insert(references).values([
{ groceryId: g1.id, reference: 'Brand A' },
{ groceryId: g2.id, reference: 'Brand B' },
]);
const refs = await service.loadForGrocery(g1.id);
expect(refs).toHaveLength(1);
expect(refs[0].reference).toBe('Brand A');
});
it('loadForGrocery orders refs by score desc, then insertion', async () => {
const now = Temporal.Now.instant().toString({
smallestUnit: 'millisecond',
});
const [g] = await db
.insert(groceries)
.values({ name: 'coffee', checked: false, createdAt: now })
.returning();
await db.insert(references).values([
{ groceryId: g.id, reference: 'A' },
{ groceryId: g.id, reference: 'B', qualityScore: 50 },
{ groceryId: g.id, reference: 'C' },
{ groceryId: g.id, reference: 'D', qualityScore: 50 },
]);
const refs = await service.loadForGrocery(g.id);
expect(refs.map((r) => r.reference)).toEqual(['B', 'D', 'A', 'C']);
});
it('add creates a reference', async () => {
const now = Temporal.Now.instant().toString({
smallestUnit: 'millisecond',
});
const [g] = await db
.insert(groceries)
.values({ name: 'pasta', checked: false, createdAt: now })
.returning();
const ref = await service.add(g.id, 'Barilla', 2.5, '€/kg', 85);
expect(ref.reference).toBe('Barilla');
expect(ref.price).toBe(2.5);
const rows = await db
.select()
.from(references)
.where(eq(references.groceryId, g.id));
expect(rows).toHaveLength(1);
});
it('promote puts the ref first and clears any sibling primary', async () => {
const now = Temporal.Now.instant().toString({
smallestUnit: 'millisecond',
});
const [g] = await db
.insert(groceries)
.values({ name: 'coffee', checked: false, createdAt: now })
.returning();
const [a] = await db
.insert(references)
.values({ groceryId: g.id, reference: 'A', qualityScore: 90 })
.returning();
const [b] = await db
.insert(references)
.values({ groceryId: g.id, reference: 'B' })
.returning();
await service.promote(b.id);
let refs = await service.loadForGrocery(g.id);
expect(refs.map((r) => r.reference)).toEqual(['B', 'A']);
await service.promote(a.id);
refs = await service.loadForGrocery(g.id);
expect(refs.map((r) => r.reference)).toEqual(['A', 'B']);
const rows = await db
.select()
.from(references)
.where(eq(references.groceryId, g.id));
expect(rows.filter((r) => r.isPrimary)).toHaveLength(1);
expect(rows.find((r) => r.id === a.id)?.isPrimary).toBe(true);
});
it('deleteReference removes the ref', async () => {
const now = Temporal.Now.instant().toString({
smallestUnit: 'millisecond',
});
const [g] = await db
.insert(groceries)
.values({ name: 'rice', checked: false, createdAt: now })
.returning();
const [ref] = await db
.insert(references)
.values({ groceryId: g.id, reference: 'Brand X' })
.returning();
await service.deleteReference(ref.id);
const rows = await db.select().from(references);
expect(rows).toHaveLength(0);
});
});
|