gitnexus 1.6.5-rc.15 → 1.6.5-rc.16
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/lbug/lbug-adapter.js +96 -40
- package/package.json +1 -1
|
@@ -167,6 +167,65 @@ const runWithSessionLock = async (operation) => {
|
|
|
167
167
|
}
|
|
168
168
|
};
|
|
169
169
|
const normalizeCopyPath = (filePath) => filePath.replace(/\\/g, '/');
|
|
170
|
+
const closeQueryResult = async (result) => {
|
|
171
|
+
try {
|
|
172
|
+
await result.close();
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// Best-effort cleanup only.
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
const drainQueryResult = async (queryResult) => {
|
|
179
|
+
const results = Array.isArray(queryResult) ? queryResult : [queryResult];
|
|
180
|
+
let firstError;
|
|
181
|
+
let hasError = false;
|
|
182
|
+
for (const result of results) {
|
|
183
|
+
try {
|
|
184
|
+
await result.getAll();
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
if (!hasError) {
|
|
188
|
+
firstError = err;
|
|
189
|
+
hasError = true;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
await closeQueryResult(result);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (hasError)
|
|
197
|
+
throw firstError;
|
|
198
|
+
};
|
|
199
|
+
const readQueryRows = async (queryResult) => {
|
|
200
|
+
const results = Array.isArray(queryResult) ? queryResult : [queryResult];
|
|
201
|
+
let rows = [];
|
|
202
|
+
let firstError;
|
|
203
|
+
let hasError = false;
|
|
204
|
+
for (let i = 0; i < results.length; i++) {
|
|
205
|
+
const result = results[i];
|
|
206
|
+
try {
|
|
207
|
+
const resultRows = await result.getAll();
|
|
208
|
+
if (i === 0)
|
|
209
|
+
rows = resultRows;
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
if (!hasError) {
|
|
213
|
+
firstError = err;
|
|
214
|
+
hasError = true;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
218
|
+
await closeQueryResult(result);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (hasError)
|
|
222
|
+
throw firstError;
|
|
223
|
+
return rows;
|
|
224
|
+
};
|
|
225
|
+
const queryAndDrain = async (targetConn, cypher) => {
|
|
226
|
+
const queryResult = await targetConn.query(cypher);
|
|
227
|
+
await drainQueryResult(queryResult);
|
|
228
|
+
};
|
|
170
229
|
export const initLbug = async (dbPath) => {
|
|
171
230
|
return runWithSessionLock(() => ensureLbugInitialized(dbPath));
|
|
172
231
|
};
|
|
@@ -262,7 +321,7 @@ const doInitLbug = async (dbPath) => {
|
|
|
262
321
|
conn = opened.conn;
|
|
263
322
|
for (const schemaQuery of SCHEMA_QUERIES) {
|
|
264
323
|
try {
|
|
265
|
-
await conn
|
|
324
|
+
await queryAndDrain(conn, schemaQuery);
|
|
266
325
|
}
|
|
267
326
|
catch (err) {
|
|
268
327
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -312,12 +371,12 @@ export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress)
|
|
|
312
371
|
const normalizedPath = normalizeCopyPath(csvPath);
|
|
313
372
|
const copyQuery = getCopyQuery(table, normalizedPath);
|
|
314
373
|
try {
|
|
315
|
-
await conn
|
|
374
|
+
await queryAndDrain(conn, copyQuery);
|
|
316
375
|
}
|
|
317
376
|
catch (err) {
|
|
318
377
|
try {
|
|
319
378
|
const retryQuery = copyQuery.replace('auto_detect=false)', 'auto_detect=false, IGNORE_ERRORS=true)');
|
|
320
|
-
await conn
|
|
379
|
+
await queryAndDrain(conn, retryQuery);
|
|
321
380
|
}
|
|
322
381
|
catch (retryErr) {
|
|
323
382
|
const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
@@ -350,12 +409,12 @@ export const loadGraphToLbug = async (graph, repoPath, storagePath, onProgress)
|
|
|
350
409
|
log(`Loading edges: ${pairIdx}/${relsByPairMeta.size} types (${fromLabel} -> ${toLabel})`);
|
|
351
410
|
}
|
|
352
411
|
try {
|
|
353
|
-
await conn
|
|
412
|
+
await queryAndDrain(conn, copyQuery);
|
|
354
413
|
}
|
|
355
414
|
catch (err) {
|
|
356
415
|
try {
|
|
357
416
|
const retryQuery = copyQuery.replace('auto_detect=false)', 'auto_detect=false, IGNORE_ERRORS=true)');
|
|
358
|
-
await conn
|
|
417
|
+
await queryAndDrain(conn, retryQuery);
|
|
359
418
|
}
|
|
360
419
|
catch (retryErr) {
|
|
361
420
|
const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
@@ -475,7 +534,7 @@ const fallbackRelationshipInserts = async (validRelLines, validTables, getNodeLa
|
|
|
475
534
|
const confidence = parseFloat(confidenceStr) || 1.0;
|
|
476
535
|
const step = parseInt(stepStr) || 0;
|
|
477
536
|
const esc = (s) => s.replace(/'/g, "''").replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/\r/g, '\\r');
|
|
478
|
-
await conn
|
|
537
|
+
await queryAndDrain(conn, `
|
|
479
538
|
MATCH (a:${escapeLabel(fromLabel)} {id: '${esc(fromId)}' }),
|
|
480
539
|
(b:${escapeLabel(toLabel)} {id: '${esc(toId)}' })
|
|
481
540
|
CREATE (a)-[:${REL_TABLE_NAME} {type: '${esc(relType)}', confidence: ${confidence}, reason: '${esc(reason)}', step: ${step}}]->(b)
|
|
@@ -589,7 +648,7 @@ export const insertNodeToLbug = async (label, properties, dbPath) => {
|
|
|
589
648
|
if (targetDbPath) {
|
|
590
649
|
const tempHandle = await openLbugConnection(lbug, targetDbPath);
|
|
591
650
|
try {
|
|
592
|
-
await tempHandle.conn
|
|
651
|
+
await queryAndDrain(tempHandle.conn, query);
|
|
593
652
|
return true;
|
|
594
653
|
}
|
|
595
654
|
finally {
|
|
@@ -598,7 +657,7 @@ export const insertNodeToLbug = async (label, properties, dbPath) => {
|
|
|
598
657
|
}
|
|
599
658
|
else if (conn) {
|
|
600
659
|
// Use existing persistent connection (when called from analyze)
|
|
601
|
-
await conn
|
|
660
|
+
await queryAndDrain(conn, query);
|
|
602
661
|
return true;
|
|
603
662
|
}
|
|
604
663
|
return false;
|
|
@@ -667,7 +726,7 @@ export const batchInsertNodesToLbug = async (nodes, dbPath) => {
|
|
|
667
726
|
: '';
|
|
668
727
|
query = `MERGE (n:${t} {id: ${escapeValue(properties.id)}}) SET n.name = ${escapeValue(properties.name)}, n.filePath = ${escapeValue(properties.filePath)}, n.startLine = ${properties.startLine || 0}, n.endLine = ${properties.endLine || 0}, n.content = ${escapeValue(properties.content || '')}${descPart}`;
|
|
669
728
|
}
|
|
670
|
-
await tempConn
|
|
729
|
+
await queryAndDrain(tempConn, query);
|
|
671
730
|
inserted++;
|
|
672
731
|
}
|
|
673
732
|
catch (e) {
|
|
@@ -686,19 +745,17 @@ export const executeQuery = async (cypher) => {
|
|
|
686
745
|
throw new Error('LadybugDB not initialized. Call initLbug first.');
|
|
687
746
|
}
|
|
688
747
|
const queryResult = await conn.query(cypher);
|
|
689
|
-
|
|
690
|
-
// Query returns QueryResult for single queries, QueryResult[] for multi-statement
|
|
691
|
-
const result = Array.isArray(queryResult) ? queryResult[0] : queryResult;
|
|
692
|
-
const rows = await result.getAll();
|
|
693
|
-
return rows;
|
|
748
|
+
return await readQueryRows(queryResult);
|
|
694
749
|
};
|
|
695
750
|
export const streamQuery = async (cypher, onRow) => {
|
|
696
751
|
if (!conn) {
|
|
697
752
|
throw new Error('LadybugDB not initialized. Call initLbug first.');
|
|
698
753
|
}
|
|
699
754
|
const queryResult = await conn.query(cypher);
|
|
700
|
-
const
|
|
755
|
+
const results = Array.isArray(queryResult) ? queryResult : [queryResult];
|
|
756
|
+
const result = results[0];
|
|
701
757
|
let rowCount = 0;
|
|
758
|
+
let streamError;
|
|
702
759
|
try {
|
|
703
760
|
while (await result.hasNext()) {
|
|
704
761
|
const row = await result.getNext();
|
|
@@ -707,12 +764,17 @@ export const streamQuery = async (cypher, onRow) => {
|
|
|
707
764
|
}
|
|
708
765
|
return rowCount;
|
|
709
766
|
}
|
|
767
|
+
catch (err) {
|
|
768
|
+
streamError = err;
|
|
769
|
+
throw err;
|
|
770
|
+
}
|
|
710
771
|
finally {
|
|
711
772
|
try {
|
|
712
|
-
await
|
|
773
|
+
await drainQueryResult(results);
|
|
713
774
|
}
|
|
714
|
-
catch {
|
|
715
|
-
|
|
775
|
+
catch (err) {
|
|
776
|
+
if (streamError === undefined)
|
|
777
|
+
throw err;
|
|
716
778
|
}
|
|
717
779
|
}
|
|
718
780
|
};
|
|
@@ -730,8 +792,7 @@ export const executePrepared = async (cypher, params) => {
|
|
|
730
792
|
throw new Error(`Prepare failed: ${errMsg}`);
|
|
731
793
|
}
|
|
732
794
|
const queryResult = await conn.execute(stmt, params);
|
|
733
|
-
|
|
734
|
-
return await result.getAll();
|
|
795
|
+
return await readQueryRows(queryResult);
|
|
735
796
|
};
|
|
736
797
|
export const executeWithReusedStatement = async (cypher, paramsList) => {
|
|
737
798
|
if (!conn) {
|
|
@@ -749,7 +810,7 @@ export const executeWithReusedStatement = async (cypher, paramsList) => {
|
|
|
749
810
|
}
|
|
750
811
|
try {
|
|
751
812
|
for (const params of subBatch) {
|
|
752
|
-
await conn.execute(stmt, params);
|
|
813
|
+
await drainQueryResult(await conn.execute(stmt, params));
|
|
753
814
|
}
|
|
754
815
|
}
|
|
755
816
|
catch (e) {
|
|
@@ -767,8 +828,7 @@ export const getLbugStats = async () => {
|
|
|
767
828
|
for (const tableName of NODE_TABLES) {
|
|
768
829
|
try {
|
|
769
830
|
const queryResult = await conn.query(`MATCH (n:${escapeTableName(tableName)}) RETURN count(n) AS cnt`);
|
|
770
|
-
const
|
|
771
|
-
const nodeRows = await nodeResult.getAll();
|
|
831
|
+
const nodeRows = await readQueryRows(queryResult);
|
|
772
832
|
if (nodeRows.length > 0) {
|
|
773
833
|
totalNodes += Number(nodeRows[0]?.cnt ?? nodeRows[0]?.[0] ?? 0);
|
|
774
834
|
}
|
|
@@ -780,8 +840,7 @@ export const getLbugStats = async () => {
|
|
|
780
840
|
let totalEdges = 0;
|
|
781
841
|
try {
|
|
782
842
|
const queryResult = await conn.query(`MATCH ()-[r:${REL_TABLE_NAME}]->() RETURN count(r) AS cnt`);
|
|
783
|
-
const
|
|
784
|
-
const edgeRows = await edgeResult.getAll();
|
|
843
|
+
const edgeRows = await readQueryRows(queryResult);
|
|
785
844
|
if (edgeRows.length > 0) {
|
|
786
845
|
totalEdges = Number(edgeRows[0]?.cnt ?? edgeRows[0]?.[0] ?? 0);
|
|
787
846
|
}
|
|
@@ -810,8 +869,7 @@ export const loadCachedEmbeddings = async () => {
|
|
|
810
869
|
// If the query fails (column missing), we return empty cache to force a full rebuild.
|
|
811
870
|
try {
|
|
812
871
|
const check = await conn.query(`MATCH (e:${EMBEDDING_TABLE_NAME}) RETURN e.nodeId AS nodeId, e.chunkIndex AS chunkIndex LIMIT 1`);
|
|
813
|
-
|
|
814
|
-
await checkResult.getAll();
|
|
872
|
+
await readQueryRows(check);
|
|
815
873
|
}
|
|
816
874
|
catch {
|
|
817
875
|
return { embeddingNodeIds: new Set(), embeddings: [] };
|
|
@@ -833,8 +891,7 @@ export const loadCachedEmbeddings = async () => {
|
|
|
833
891
|
throw err;
|
|
834
892
|
}
|
|
835
893
|
}
|
|
836
|
-
const
|
|
837
|
-
for (const row of await result.getAll()) {
|
|
894
|
+
for (const row of await readQueryRows(rows)) {
|
|
838
895
|
const nodeId = String(row.nodeId ?? row[0] ?? '');
|
|
839
896
|
if (!nodeId)
|
|
840
897
|
continue;
|
|
@@ -938,7 +995,8 @@ export const flushWAL = async () => {
|
|
|
938
995
|
if (!conn)
|
|
939
996
|
return;
|
|
940
997
|
try {
|
|
941
|
-
await conn.query('CHECKPOINT');
|
|
998
|
+
const checkpointResult = await conn.query('CHECKPOINT');
|
|
999
|
+
await drainQueryResult(checkpointResult);
|
|
942
1000
|
}
|
|
943
1001
|
catch {
|
|
944
1002
|
/* ignore — older LadybugDB or schemaless DB may not accept it */
|
|
@@ -1036,12 +1094,11 @@ export const deleteNodesForFile = async (filePath, dbPath) => {
|
|
|
1036
1094
|
// First count how many we'll delete
|
|
1037
1095
|
const tn = escapeTableName(tableName);
|
|
1038
1096
|
const countResult = await targetConn.query(`MATCH (n:${tn}) WHERE n.filePath = '${escapedPath}' RETURN count(n) AS cnt`);
|
|
1039
|
-
const
|
|
1040
|
-
const rows = await result.getAll();
|
|
1097
|
+
const rows = await readQueryRows(countResult);
|
|
1041
1098
|
const count = Number(rows[0]?.cnt ?? rows[0]?.[0] ?? 0);
|
|
1042
1099
|
if (count > 0) {
|
|
1043
1100
|
// Delete nodes (and implicitly their relationships via DETACH)
|
|
1044
|
-
await targetConn
|
|
1101
|
+
await queryAndDrain(targetConn, `MATCH (n:${tn}) WHERE n.filePath = '${escapedPath}' DETACH DELETE n`);
|
|
1045
1102
|
deletedNodes += count;
|
|
1046
1103
|
}
|
|
1047
1104
|
}
|
|
@@ -1051,7 +1108,7 @@ export const deleteNodesForFile = async (filePath, dbPath) => {
|
|
|
1051
1108
|
}
|
|
1052
1109
|
// Also delete any embeddings for nodes in this file
|
|
1053
1110
|
try {
|
|
1054
|
-
await targetConn
|
|
1111
|
+
await queryAndDrain(targetConn, `MATCH (e:${EMBEDDING_TABLE_NAME}) WHERE e.nodeId STARTS WITH '${escapedPath}' DELETE e`);
|
|
1055
1112
|
}
|
|
1056
1113
|
catch {
|
|
1057
1114
|
// Embedding table may not exist or nodeId format may differ
|
|
@@ -1158,7 +1215,7 @@ export const loadFTSExtension = async (targetConn, opts = {}) => {
|
|
|
1158
1215
|
if (!c) {
|
|
1159
1216
|
throw new Error('LadybugDB not initialized. Call initLbug first.');
|
|
1160
1217
|
}
|
|
1161
|
-
const loaded = await extensionManager.ensure((sql) => c
|
|
1218
|
+
const loaded = await extensionManager.ensure((sql) => queryAndDrain(c, sql), 'fts', 'FTS', opts);
|
|
1162
1219
|
if (loaded && useModuleState)
|
|
1163
1220
|
ftsLoaded = true;
|
|
1164
1221
|
return loaded;
|
|
@@ -1186,7 +1243,7 @@ export const loadVectorExtension = async (targetConn, opts = {}) => {
|
|
|
1186
1243
|
if (!c) {
|
|
1187
1244
|
throw new Error('LadybugDB not initialized. Call initLbug first.');
|
|
1188
1245
|
}
|
|
1189
|
-
const loaded = await extensionManager.ensure((sql) => c
|
|
1246
|
+
const loaded = await extensionManager.ensure((sql) => queryAndDrain(c, sql), 'VECTOR', 'VECTOR', opts);
|
|
1190
1247
|
if (loaded && useModuleState)
|
|
1191
1248
|
vectorExtensionLoaded = true;
|
|
1192
1249
|
return loaded;
|
|
@@ -1211,7 +1268,7 @@ export const createFTSIndex = async (tableName, indexName, properties, stemmer =
|
|
|
1211
1268
|
const propList = properties.map((p) => `'${p}'`).join(', ');
|
|
1212
1269
|
const query = `CALL CREATE_FTS_INDEX('${tableName}', '${indexName}', [${propList}], stemmer := '${stemmer}')`;
|
|
1213
1270
|
try {
|
|
1214
|
-
await conn
|
|
1271
|
+
await queryAndDrain(conn, query);
|
|
1215
1272
|
ensuredFTSIndexes.add(key);
|
|
1216
1273
|
}
|
|
1217
1274
|
catch (e) {
|
|
@@ -1280,8 +1337,7 @@ export const queryFTS = async (tableName, indexName, query, limit = 20, conjunct
|
|
|
1280
1337
|
`;
|
|
1281
1338
|
try {
|
|
1282
1339
|
const queryResult = await conn.query(cypher);
|
|
1283
|
-
const
|
|
1284
|
-
const rows = await result.getAll();
|
|
1340
|
+
const rows = await readQueryRows(queryResult);
|
|
1285
1341
|
return rows.map((row) => {
|
|
1286
1342
|
const node = row.node || row[0] || {};
|
|
1287
1343
|
const score = row.score ?? row[1] ?? 0;
|
|
@@ -1310,7 +1366,7 @@ export const dropFTSIndex = async (tableName, indexName) => {
|
|
|
1310
1366
|
throw new Error('LadybugDB not initialized. Call initLbug first.');
|
|
1311
1367
|
}
|
|
1312
1368
|
try {
|
|
1313
|
-
await conn
|
|
1369
|
+
await queryAndDrain(conn, `CALL DROP_FTS_INDEX('${tableName}', '${indexName}')`);
|
|
1314
1370
|
}
|
|
1315
1371
|
catch {
|
|
1316
1372
|
// Index may not exist
|
package/package.json
CHANGED