@substrat-run/contract-tests 0.79.0 → 0.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ import type { ScopeHostFixture } from './scope-host-suite.js';
2
+ export declare function searchContractSuite(adapterName: string, makeFixture: () => Promise<ScopeHostFixture>): void;
3
+ //# sourceMappingURL=search-suite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-suite.d.ts","sourceRoot":"","sources":["../src/search-suite.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAW9D,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC,GAC3C,IAAI,CAoMN"}
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Contract suite for `ctx.search` — the derived FTS index (#827).
3
+ *
4
+ * What it pins: **a declaration is enough.** A module says which entity and
5
+ * which fields are searchable and gets a working index in every scope, on every
6
+ * adapter, maintained by whoever writes the row — including a writer that has
7
+ * never heard of the index.
8
+ *
9
+ * The assertions are deliberately behavioural rather than structural. An earlier
10
+ * draft of the emitter produced SQL that read correctly and failed at prepare
11
+ * time (`MATCH` takes the table's own name, so aliasing the FTS table breaks it),
12
+ * which a string comparison would have called a pass — the same lesson as the FK
13
+ * that shipped behind passing string assertions. So every case here provisions a
14
+ * real scope, writes real rows, and asks a real question.
15
+ *
16
+ * It is also where the two hosts are held to the same answer. Durable Object
17
+ * SQLite and better-sqlite3 both ship FTS5, but only one of them has a
18
+ * `SqlStorageRegulator` deciding whether a trigger may run at all — a fact no
19
+ * amount of local green would have surfaced.
20
+ */
21
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
22
+ import { permissionKey, platformActorId, principalId, scopeId, tenantId, } from '@substrat-run/contracts';
23
+ import { ulid } from '@substrat-run/kernel';
24
+ import { searchMod } from './modules.js';
25
+ const PERM_USE = permissionKey.parse('search:use');
26
+ export function searchContractSuite(adapterName, makeFixture) {
27
+ describe(`search (ctx.search): ${adapterName}`, () => {
28
+ let fixture;
29
+ let host;
30
+ let stub;
31
+ let source;
32
+ const t1 = tenantId.parse(ulid());
33
+ const alice = principalId.parse(ulid());
34
+ const staff = platformActorId.parse(ulid());
35
+ const find = (entityType, term, limit) => stub.invoke('search/find', { entityType, term, limit });
36
+ const ids = async (entityType, term, limit) => (await find(entityType, term, limit)).map((h) => h.id);
37
+ beforeAll(async () => {
38
+ fixture = await makeFixture();
39
+ host = fixture.host;
40
+ host.registerModule(searchMod);
41
+ await host.admin.createTenant(staff, { id: t1, slug: 'search-tenant', name: 'Search Tenant' });
42
+ await host.admin.grantEntitlement(staff, t1, 'search');
43
+ await host.admin.defineRole(staff, t1, {
44
+ key: 'search-admin',
45
+ permissions: [PERM_USE],
46
+ source: 'vertical',
47
+ });
48
+ await host.admin.assignRole(staff, {
49
+ principalId: alice,
50
+ roleKey: 'search-admin',
51
+ node: { tenantId: t1, scopeId: null },
52
+ });
53
+ source = scopeId.parse(ulid());
54
+ await host.provisionScope(staff, { tenantId: t1, scopeId: source, vertical: 'search-vertical' });
55
+ await host.admin.activateScope(staff, t1, source);
56
+ stub = await host.getScope(alice, t1, source);
57
+ await stub.invoke('search/add', { id: 'c1', number: '1001', name: 'Andersson Fastigheter AB' });
58
+ await stub.invoke('search/add', { id: 'c2', number: '1002', name: 'Bergqvist & Söner' });
59
+ await stub.invoke('search/add', { id: 'c3', number: '1003', name: 'Cederlund Andersson VVS' });
60
+ });
61
+ afterAll(async () => {
62
+ await fixture.cleanup();
63
+ });
64
+ // -- the headline case ---------------------------------------------------
65
+ it('finds a row by a prefix of one word in a declared field', async () => {
66
+ await expect(ids('searchcustomer', 'anders')).resolves.toEqual(expect.arrayContaining(['c1', 'c3']));
67
+ });
68
+ it('finds by a second declared field — the number, not just the name', async () => {
69
+ await expect(ids('searchcustomer', '1002')).resolves.toEqual(['c2']);
70
+ });
71
+ /**
72
+ * The case that changed the emitter. Prefixing only the LAST term is the
73
+ * obvious rule and it silently returns nothing here: `unicode61` indexes
74
+ * whole words, so "fast" matches "Fastigheter" only as a prefix.
75
+ */
76
+ it('treats EVERY term as a prefix, so a half-typed first word still matches', async () => {
77
+ await expect(ids('searchcustomer', 'anders fast')).resolves.toEqual(['c1']);
78
+ });
79
+ it('ranks by relevance, not by insertion order', async () => {
80
+ const hits = await find('searchcustomer', 'andersson');
81
+ expect(hits.map((h) => h.id).sort()).toEqual(['c1', 'c3']);
82
+ // bm25 is negative and lower is better; the suite pins the ORDER it implies.
83
+ expect(hits[0].rank).toBeLessThanOrEqual(hits[1].rank);
84
+ });
85
+ it('matches non-ASCII text as typed', async () => {
86
+ await expect(ids('searchcustomer', 'söner')).resolves.toEqual(['c2']);
87
+ });
88
+ // -- what a person can type ----------------------------------------------
89
+ /**
90
+ * FTS5's query language has operators and a picker's input is a name. Someone
91
+ * searching for `AND` must get rows or nothing — never a syntax error, and
92
+ * never a match they did not ask for.
93
+ */
94
+ it('treats query syntax as literal text rather than as operators', async () => {
95
+ await expect(find('searchcustomer', 'AND "x* OR')).resolves.toEqual([]);
96
+ await expect(ids('searchcustomer', 'bergqvist OR anders')).resolves.toEqual([]);
97
+ });
98
+ it('refuses a term below the index floor instead of scanning the scope', async () => {
99
+ await expect(find('searchcustomer', 'a')).rejects.toThrow(/shorter than 2/);
100
+ });
101
+ it('refuses an entity type no module declared searchable', async () => {
102
+ await expect(find('nosuchentity', 'anders')).rejects.toThrow(/declares no searchable fields/);
103
+ });
104
+ // -- the index stays in step ---------------------------------------------
105
+ it('sees a row written by a caller that knows nothing about the index', async () => {
106
+ await stub.invoke('search/add', { id: 'c4', number: '1004', name: 'Dahlgren El' });
107
+ await expect(ids('searchcustomer', 'dahlgren')).resolves.toEqual(['c4']);
108
+ });
109
+ it('drops the old text on update and carries the new', async () => {
110
+ await stub.invoke('search/rename', { id: 'c4', name: 'Ekström El' });
111
+ await expect(find('searchcustomer', 'dahlgren')).resolves.toEqual([]);
112
+ await expect(ids('searchcustomer', 'ekström')).resolves.toEqual(['c4']);
113
+ });
114
+ it('forgets a deleted row', async () => {
115
+ await stub.invoke('search/remove', { id: 'c4' });
116
+ await expect(find('searchcustomer', 'ekström')).resolves.toEqual([]);
117
+ });
118
+ /**
119
+ * The guarantee that decided triggers over indexing off the event spine. An
120
+ * eventually-consistent index makes this case fail for a second or two — long
121
+ * enough that the picker a user hits right after creating a customer is empty,
122
+ * which is the bug report. Stripe documents exactly this caveat; we do not
123
+ * have to inherit it.
124
+ */
125
+ it('is readable in the SAME transaction that wrote the row', async () => {
126
+ const hits = await stub.invoke('search/add-then-find', {
127
+ id: 'c5',
128
+ number: '1005',
129
+ name: 'Forsberg Fastighetsservice',
130
+ term: 'forsberg',
131
+ });
132
+ expect(hits.map((h) => h.id)).toEqual(['c5']);
133
+ });
134
+ // -- the declared tokenizer actually differs ------------------------------
135
+ describe('tokenizer', () => {
136
+ beforeAll(async () => {
137
+ await stub.invoke('search/add-note', { id: 'n1', body: 'Nyckelskåpet vid entrén' });
138
+ });
139
+ it('substring matches INSIDE a word, which prefix does not', async () => {
140
+ await expect(ids('searchnote', 'skåp')).resolves.toEqual(['n1']);
141
+ // The same query shape against the prefix-tokenized entity finds nothing:
142
+ // 'ndersson' is inside 'Andersson' but is not a prefix of any token.
143
+ await expect(find('searchcustomer', 'ndersson')).resolves.toEqual([]);
144
+ });
145
+ it('applies the substring floor of three characters', async () => {
146
+ await expect(find('searchnote', 'ny')).rejects.toThrow(/shorter than 3/);
147
+ });
148
+ });
149
+ // -- a fork carries the rows, and rebuilds the index ----------------------
150
+ /**
151
+ * The index is derived data, and the dump treats it that way: excluded on
152
+ * export (its shadow tables cannot be replayed — the DO host rejects the name,
153
+ * and D1's own exporter refuses a database containing an fts5 table at all),
154
+ * rebuilt on import from the rows that just landed.
155
+ *
156
+ * What this pins is the part a user would notice: a forked scope searches
157
+ * immediately, with nobody re-indexing it by hand.
158
+ */
159
+ it('survives a fork — the copy searches without a manual re-index', async () => {
160
+ const dump = await host.admin.exportScope(staff, t1, source);
161
+ expect(dump.tables.some((t) => t.name.startsWith('_substrat_search_'))).toBe(false);
162
+ // The rows themselves are in the dump; it is the index over them that is not.
163
+ const customers = dump.tables.find((t) => t.name === 'search_customers');
164
+ expect(customers?.rows.length).toBeGreaterThan(0);
165
+ const copyId = scopeId.parse(ulid());
166
+ await host.importScope(staff, { tenantId: t1, scopeId: copyId, vertical: 'search-vertical' }, dump);
167
+ const copy = await host.getScope(alice, t1, copyId);
168
+ const hits = await copy.invoke('search/find', {
169
+ entityType: 'searchcustomer',
170
+ term: 'anders',
171
+ });
172
+ expect(hits.map((h) => h.id).sort()).toEqual(['c1', 'c3']);
173
+ // And the triggers came back with it: the copy indexes its OWN later writes.
174
+ await copy.invoke('search/add', { id: 'c9', number: '1009', name: 'Gustafsson Rör' });
175
+ const later = await copy.invoke('search/find', {
176
+ entityType: 'searchcustomer',
177
+ term: 'gustafsson',
178
+ });
179
+ expect(later.map((h) => h.id)).toEqual(['c9']);
180
+ });
181
+ // -- the cap is the pagination story --------------------------------------
182
+ it('caps the result set rather than pretending to paginate a ranked read', async () => {
183
+ await expect(ids('searchcustomer', 'anders', 1)).resolves.toHaveLength(1);
184
+ });
185
+ });
186
+ }
187
+ //# sourceMappingURL=search-suite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-suite.js","sourceRoot":"","sources":["../src/search-suite.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@substrat-run/contract-tests",
3
- "version": "0.79.0",
3
+ "version": "0.81.0",
4
4
  "description": "The suite every scope-host adapter must pass, forever (D-14)",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
@@ -23,8 +23,8 @@
23
23
  ],
24
24
  "dependencies": {
25
25
  "vitest": "^3.2.7",
26
- "@substrat-run/contracts": "^0.79.0",
27
- "@substrat-run/kernel": "^0.79.0"
26
+ "@substrat-run/contracts": "^0.81.0",
27
+ "@substrat-run/kernel": "^0.81.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/node": "^22.0.0",