gitnexus 1.6.9-rc.21 → 1.6.9-rc.22
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.
package/dist/core/run-analyze.js
CHANGED
|
@@ -353,6 +353,20 @@ export async function runFullAnalysis(repoPath, options, callbacks) {
|
|
|
353
353
|
}
|
|
354
354
|
try {
|
|
355
355
|
await initLbug(lbugPath);
|
|
356
|
+
// Gate on FTS availability BEFORE touching any index. createSearchFTSIndexes
|
|
357
|
+
// now DROPs each index before recreating it (so schema changes reach existing
|
|
358
|
+
// DBs); if the extension were unavailable, the drops would run and leave the
|
|
359
|
+
// DB index-less, only failing at the create step. Fail loudly first — mirrors
|
|
360
|
+
// the analyze path's `if (ftsAvailable)` gate below — so an unavailable
|
|
361
|
+
// extension never destroys the existing indexes.
|
|
362
|
+
const repairFtsAvailable = await loadFTSExtension(undefined, {
|
|
363
|
+
policy: resolveAnalyzeInstallPolicy(),
|
|
364
|
+
});
|
|
365
|
+
if (!repairFtsAvailable) {
|
|
366
|
+
throw new Error('Cannot repair FTS indexes: the LadybugDB FTS extension is unavailable ' +
|
|
367
|
+
'(not pre-installed and could not be installed on this machine). ' +
|
|
368
|
+
'Run `gitnexus doctor` to install it, then retry `--repair-fts`.');
|
|
369
|
+
}
|
|
356
370
|
progress('fts', 85, 'Repairing search indexes...');
|
|
357
371
|
await createSearchFTSIndexes({
|
|
358
372
|
onIndexStart: options.verbose
|
|
@@ -1,32 +1,48 @@
|
|
|
1
|
-
import { createFTSIndex } from '../lbug/lbug-adapter.js';
|
|
1
|
+
import { createFTSIndex, dropFTSIndex } from '../lbug/lbug-adapter.js';
|
|
2
2
|
import { FTS_INDEXES } from './fts-schema.js';
|
|
3
3
|
export async function createSearchFTSIndexes(options) {
|
|
4
4
|
for (const { table, indexName, properties } of FTS_INDEXES) {
|
|
5
5
|
options?.onIndexStart?.(table, indexName);
|
|
6
|
+
// Drop first so the live `properties` always win. `createFTSIndex` is
|
|
7
|
+
// idempotent-by-name (skips when the index already exists), so without the
|
|
8
|
+
// drop a schema change — e.g. adding `description` (#2299) — would never
|
|
9
|
+
// reach an existing `.lbug` DB on an incremental re-analyze or `--repair-fts`;
|
|
10
|
+
// the old name+content index would silently persist. `dropFTSIndex` no-ops
|
|
11
|
+
// when the index is absent (first-ever analyze) and clears the per-connection
|
|
12
|
+
// memo so the create below actually runs.
|
|
13
|
+
// ponytail: this rebuilds every FTS index on every analyze instead of
|
|
14
|
+
// skipping when present; FTS build is proportional to symbol-table size and
|
|
15
|
+
// runs inside the existing FTS phase. Gate on a stored schema fingerprint if
|
|
16
|
+
// this rebuild cost ever shows up in analyze profiles.
|
|
17
|
+
await dropFTSIndex(table, indexName);
|
|
6
18
|
await createFTSIndex(table, indexName, [...properties]);
|
|
7
19
|
options?.onIndexReady?.(table, indexName);
|
|
8
20
|
}
|
|
9
21
|
}
|
|
10
22
|
export async function verifySearchFTSIndexes(executeQuery) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
// Read the catalog once and check each configured index both EXISTS and
|
|
24
|
+
// covers its expected columns. A queryability-only probe (CALL QUERY_FTS_INDEX
|
|
25
|
+
// ... catch) is not enough: a stale `name+content`-only index left on a
|
|
26
|
+
// pre-#2299 DB stays queryable yet silently misses `description`, so the probe
|
|
27
|
+
// would pass while doc-comment search is still broken (#2299). SHOW_INDEXES
|
|
28
|
+
// exposes `property_names` (STRING[]) per index, so we assert coverage directly.
|
|
29
|
+
const rows = await executeQuery('CALL SHOW_INDEXES() RETURN *');
|
|
30
|
+
const propsByIndex = new Map();
|
|
31
|
+
for (const row of rows) {
|
|
32
|
+
if (typeof row !== 'object' || row === null)
|
|
33
|
+
continue;
|
|
34
|
+
const record = row;
|
|
35
|
+
const indexName = record.index_name;
|
|
36
|
+
const propertyNames = record.property_names;
|
|
37
|
+
if (typeof indexName !== 'string' || !Array.isArray(propertyNames))
|
|
38
|
+
continue;
|
|
39
|
+
propsByIndex.set(indexName, propertyNames.filter((p) => typeof p === 'string'));
|
|
40
|
+
}
|
|
17
41
|
const missing = [];
|
|
18
|
-
for (const { table, indexName } of FTS_INDEXES) {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
CALL QUERY_FTS_INDEX('${safeTable}', '${safeIndex}', '__gitnexus_fts_probe__', conjunctive := false)
|
|
23
|
-
RETURN score
|
|
24
|
-
LIMIT 1
|
|
25
|
-
`;
|
|
26
|
-
try {
|
|
27
|
-
await executeQuery(probe);
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
42
|
+
for (const { table, indexName, properties } of FTS_INDEXES) {
|
|
43
|
+
const actual = propsByIndex.get(indexName);
|
|
44
|
+
// Absent from the catalog, or present but not covering every expected column.
|
|
45
|
+
if (!actual || !properties.every((p) => actual.includes(p))) {
|
|
30
46
|
missing.push(`${table}.${indexName}`);
|
|
31
47
|
}
|
|
32
48
|
}
|
|
@@ -1,7 +1,40 @@
|
|
|
1
|
+
// Shared by both index creation (`createSearchFTSIndexes`) and querying
|
|
2
|
+
// (`searchFTSFromLbug` / `verifySearchFTSIndexes`) — the single source of truth
|
|
3
|
+
// for which tables/columns are full-text searchable. Adding `description` here
|
|
4
|
+
// makes doc comments (Javadoc/KDoc/JSDoc/Doxygen/godoc/RDoc) keyword-searchable
|
|
5
|
+
// once they are populated by `descriptionExtractor` (#2270/#2286, issue #2299).
|
|
6
|
+
//
|
|
7
|
+
// IMPORTANT: every property must be a real column on its table (see
|
|
8
|
+
// `core/lbug/schema.ts`). `File` has no `description` column, so it stays
|
|
9
|
+
// name+content. All other entries below carry a `description` column.
|
|
10
|
+
//
|
|
11
|
+
// Tables beyond the original 5 mirror `EMBEDDABLE_LABELS` (embeddings/types.ts):
|
|
12
|
+
// indexing the same set keeps a symbol's doc comment both keyword- and
|
|
13
|
+
// semantically-searchable.
|
|
14
|
+
const FTS_PROPERTIES = ['name', 'content', 'description'];
|
|
1
15
|
export const FTS_INDEXES = [
|
|
16
|
+
// File has no `description` column — keep it name+content only.
|
|
2
17
|
{ table: 'File', indexName: 'file_fts', properties: ['name', 'content'] },
|
|
3
|
-
|
|
4
|
-
{ table: '
|
|
5
|
-
{ table: '
|
|
6
|
-
{ table: '
|
|
18
|
+
// Original 5 (minus File) gain `description`.
|
|
19
|
+
{ table: 'Function', indexName: 'function_fts', properties: FTS_PROPERTIES },
|
|
20
|
+
{ table: 'Class', indexName: 'class_fts', properties: FTS_PROPERTIES },
|
|
21
|
+
{ table: 'Method', indexName: 'method_fts', properties: FTS_PROPERTIES },
|
|
22
|
+
{ table: 'Interface', indexName: 'interface_fts', properties: FTS_PROPERTIES },
|
|
23
|
+
// Remaining EMBEDDABLE_LABELS symbol tables — all CODE_ELEMENT_BASE-shaped
|
|
24
|
+
// (or a superset), so all carry name + content + description columns.
|
|
25
|
+
{ table: 'Constructor', indexName: 'constructor_fts', properties: FTS_PROPERTIES },
|
|
26
|
+
{ table: 'Struct', indexName: 'struct_fts', properties: FTS_PROPERTIES },
|
|
27
|
+
{ table: 'Enum', indexName: 'enum_fts', properties: FTS_PROPERTIES },
|
|
28
|
+
{ table: 'Trait', indexName: 'trait_fts', properties: FTS_PROPERTIES },
|
|
29
|
+
{ table: 'Impl', indexName: 'impl_fts', properties: FTS_PROPERTIES },
|
|
30
|
+
{ table: 'Macro', indexName: 'macro_fts', properties: FTS_PROPERTIES },
|
|
31
|
+
{ table: 'Namespace', indexName: 'namespace_fts', properties: FTS_PROPERTIES },
|
|
32
|
+
{ table: 'TypeAlias', indexName: 'type_alias_fts', properties: FTS_PROPERTIES },
|
|
33
|
+
{ table: 'Typedef', indexName: 'typedef_fts', properties: FTS_PROPERTIES },
|
|
34
|
+
{ table: 'Const', indexName: 'const_fts', properties: FTS_PROPERTIES },
|
|
35
|
+
{ table: 'Property', indexName: 'property_fts', properties: FTS_PROPERTIES },
|
|
36
|
+
{ table: 'Record', indexName: 'record_fts', properties: FTS_PROPERTIES },
|
|
37
|
+
{ table: 'Union', indexName: 'union_fts', properties: FTS_PROPERTIES },
|
|
38
|
+
{ table: 'Static', indexName: 'static_fts', properties: FTS_PROPERTIES },
|
|
39
|
+
{ table: 'Variable', indexName: 'variable_fts', properties: FTS_PROPERTIES },
|
|
7
40
|
];
|
package/package.json
CHANGED
|
@@ -70,6 +70,7 @@ const LBUG_NATIVE = [
|
|
|
70
70
|
'test/integration/local-backend-calltool.test.ts',
|
|
71
71
|
'test/integration/search-core.test.ts',
|
|
72
72
|
'test/integration/search-pool.test.ts',
|
|
73
|
+
'test/integration/fts-description-search.test.ts',
|
|
73
74
|
'test/integration/staleness-and-stability.test.ts',
|
|
74
75
|
'test/integration/analyze-wal-checkpoint-failure.test.ts',
|
|
75
76
|
];
|