Drop collections and path_contexts tables from schema
- Remove collections and path_contexts table creation from initializeDatabase() - Update all queries to work without these tables - Remove JOINs with collections table from document retrieval functions - Compute absolute file paths from YAML collections in application code - Update deleteContext() to use collection names instead of IDs - Update qmd.ts status command to use listCollections() from YAML - Deprecate cleanupDuplicateCollections() (returns 0) All collection and context metadata is now managed exclusively in YAML at ~/.config/qmd/index.yml. Database contains only documents and content (content-addressable storage). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
20e5b2269a
commit
f109193e62
@ -8,7 +8,7 @@
|
||||
{"id":"qmd-6s5","title":"Export current database to index.yml","description":"Write a script to export current collections and path_contexts from SQLite to ~/.config/qmd/index.yml format. Include all collection metadata and contexts.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-13T09:54:52.707844-05:00","updated_at":"2025-12-13T09:57:36.650437-05:00","closed_at":"2025-12-13T09:57:36.650437-05:00","dependencies":[{"issue_id":"qmd-6s5","depends_on_id":"qmd-3z9","type":"blocks","created_at":"2025-12-13T09:55:07.606834-05:00","created_by":"daemon"}]}
|
||||
{"id":"qmd-7ss","title":"remove all the symlinks and stuff in the git repo, clean up the root directory","description":"","status":"closed","priority":4,"issue_type":"task","created_at":"2025-12-12T16:40:00.744982-05:00","updated_at":"2025-12-12T17:11:18.034215-05:00","closed_at":"2025-12-12T17:11:18.034215-05:00"}
|
||||
{"id":"qmd-8eu","title":"Update documents table schema for collection names","description":"Change documents.collection_id (integer FK) to documents.collection (text). Update all queries and indices. Keep backwards compatibility during transition.","design":"Schema change:\n- Add `collection TEXT` column\n- Migrate data: UPDATE documents SET collection = (SELECT name FROM collections WHERE id = collection_id)\n- Drop collection_id column\n- Update FTS5 trigger\n- Update all queries in store.ts","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-13T09:54:52.830305-05:00","updated_at":"2025-12-13T10:08:24.88716-05:00","closed_at":"2025-12-13T10:08:24.88716-05:00","dependencies":[{"issue_id":"qmd-8eu","depends_on_id":"qmd-6s5","type":"blocks","created_at":"2025-12-13T09:55:07.662048-05:00","created_by":"daemon"}]}
|
||||
{"id":"qmd-9ua","title":"Update all qmd commands for YAML-based collections","description":"Update qmd.ts commands: collection add/list/remove/rename, status, update, ls. All should use collections.ts instead of store.ts collection functions.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-13T09:54:53.14644-05:00","updated_at":"2025-12-13T09:54:53.14644-05:00","dependencies":[{"issue_id":"qmd-9ua","depends_on_id":"qmd-u84","type":"blocks","created_at":"2025-12-13T09:55:07.893268-05:00","created_by":"daemon"},{"issue_id":"qmd-9ua","depends_on_id":"qmd-oxy","type":"blocks","created_at":"2025-12-13T09:55:07.942221-05:00","created_by":"daemon"}]}
|
||||
{"id":"qmd-9ua","title":"Update all qmd commands for YAML-based collections","description":"Update qmd.ts commands: collection add/list/remove/rename, status, update, ls. All should use collections.ts instead of store.ts collection functions.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-13T09:54:53.14644-05:00","updated_at":"2025-12-13T10:17:39.67707-05:00","closed_at":"2025-12-13T10:17:39.67707-05:00","dependencies":[{"issue_id":"qmd-9ua","depends_on_id":"qmd-u84","type":"blocks","created_at":"2025-12-13T09:55:07.893268-05:00","created_by":"daemon"},{"issue_id":"qmd-9ua","depends_on_id":"qmd-oxy","type":"blocks","created_at":"2025-12-13T09:55:07.942221-05:00","created_by":"daemon"}]}
|
||||
{"id":"qmd-afe","title":"implement qmd collection rename, which changes the global path prefix for the collection","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-12T15:55:54.779325-05:00","updated_at":"2025-12-12T16:29:24.153196-05:00","closed_at":"2025-12-12T16:29:24.153196-05:00"}
|
||||
{"id":"qmd-ama","title":"Refactor database system","description":"All documents should be stored as content addressable hash, e.g. hash, doc, created_at,\n┃ updated_at. documents should be a file system layer on top e.g. collection, path, hash,\n┃ created_at, updated_at. (collection,path)\n┃\n┃\n\n┃ All documents should be stored as content addressable hash, e.g. hash, doc, created_at,\n┃ updated_at. documents should be a file system layer on top e.g. collection_id, path, hash,\n┃ created_at, updated_at. (collection,path) is unique. There is also collection which stores PWD\n┃ + glob pattern, name (\\w+). Every document is treated as path qmd://collection.name/","notes":"## Completed\n- ✅ Implemented content-addressable storage (content table with hash→doc mapping)\n- ✅ Refactored documents table as file system layer (collection_id, path, hash)\n- ✅ Added collection names (e.g., \"pages\", \"journals\", \"archive\")\n- ✅ Implemented virtual paths (qmd://collection-name/path/to/file.md)\n- ✅ Added hierarchical context support (collection-scoped)\n- ✅ Successfully migrated existing database\n- ✅ Updated search functions to work with new schema\n- ✅ Updated indexing logic to use content-addressable storage\n- ✅ Orphaned content hash cleanup\n\n## Still TODO\n- Fix migration SQL to properly extract basename (currently needs manual fix)\n- Implement `qmd collection add . --name \u003cname\u003e --mask '**/*.md'`\n- Implement `qmd ls [path]` for exploring virtual file tree","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-10T10:57:35.497489-05:00","updated_at":"2025-12-12T15:39:48.879143-05:00","closed_at":"2025-12-12T15:39:48.879143-05:00"}
|
||||
{"id":"qmd-bs8","title":"Update documentation for YAML configuration","description":"Update CLAUDE.md, README.md with new YAML configuration approach. Document index.yml format and manual editing instructions.","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-13T09:54:53.449584-05:00","updated_at":"2025-12-13T09:54:53.449584-05:00","dependencies":[{"issue_id":"qmd-bs8","depends_on_id":"qmd-1xd","type":"blocks","created_at":"2025-12-13T09:55:08.264615-05:00","created_by":"daemon"}]}
|
||||
@ -28,7 +28,7 @@
|
||||
{"id":"qmd-rck","title":"move the source files to src/*, clean up teh directory","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-12T16:40:19.198119-05:00","updated_at":"2025-12-12T17:12:22.502746-05:00","closed_at":"2025-12-12T17:12:22.502746-05:00"}
|
||||
{"id":"qmd-rhd","title":"Fix 'qmd status' output for new schema","description":"Update status to show collections by name, cleaner context display, virtual path examples.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-12T15:29:54.020596-05:00","updated_at":"2025-12-12T16:13:28.08389-05:00","closed_at":"2025-12-12T16:13:28.08389-05:00","dependencies":[{"issue_id":"qmd-rhd","depends_on_id":"qmd-ama","type":"discovered-from","created_at":"2025-12-12T15:29:54.021095-05:00","created_by":"daemon"}]}
|
||||
{"id":"qmd-s1y","title":"Update 'qmd add-context' for collection scoping","description":"Update add-context to work with collection-scoped contexts using new path_contexts schema.","notes":"Refactoring to:\n- qmd context add [path] \"text\" (defaults to current collection if in one)\n- qmd context list\n- qmd context rm \u003cpath\u003e\n- Support \"/\" for global/system context\n- Auto-detect collection from pwd","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-12T15:29:54.076582-05:00","updated_at":"2025-12-12T15:37:47.683263-05:00","closed_at":"2025-12-12T15:37:47.683263-05:00"}
|
||||
{"id":"qmd-thw","title":"Drop collections and path_contexts tables","description":"Remove collections and path_contexts tables from schema. Update initDb() to not create these tables. Only keep documents, content, and search indices.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-13T09:54:53.247136-05:00","updated_at":"2025-12-13T09:54:53.247136-05:00","dependencies":[{"issue_id":"qmd-thw","depends_on_id":"qmd-9ua","type":"blocks","created_at":"2025-12-13T09:55:08.027101-05:00","created_by":"daemon"}]}
|
||||
{"id":"qmd-thw","title":"Drop collections and path_contexts tables","description":"Remove collections and path_contexts tables from schema. Update initDb() to not create these tables. Only keep documents, content, and search indices.","status":"in_progress","priority":1,"issue_type":"task","created_at":"2025-12-13T09:54:53.247136-05:00","updated_at":"2025-12-13T10:20:15.923202-05:00","dependencies":[{"issue_id":"qmd-thw","depends_on_id":"qmd-9ua","type":"blocks","created_at":"2025-12-13T09:55:08.027101-05:00","created_by":"daemon"}]}
|
||||
{"id":"qmd-u84","title":"Refactor store.ts to use collections.ts","description":"Replace all collection DB queries with collections.ts calls. Remove getCollectionById, getCollectionByName, listCollections DB functions. Use YAML config instead.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-13T09:54:52.936782-05:00","updated_at":"2025-12-13T10:16:07.681047-05:00","closed_at":"2025-12-13T10:16:07.681047-05:00","dependencies":[{"issue_id":"qmd-u84","depends_on_id":"qmd-3z9","type":"blocks","created_at":"2025-12-13T09:55:07.720439-05:00","created_by":"daemon"},{"issue_id":"qmd-u84","depends_on_id":"qmd-8eu","type":"blocks","created_at":"2025-12-13T09:55:07.782051-05:00","created_by":"daemon"}]}
|
||||
{"id":"qmd-vro","title":"Update 'qmd get' to support virtual paths","description":"Allow qmd get to accept both virtual paths (qmd://journals/...) and filesystem paths, plus fuzzy matching by filename.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-12T15:29:53.963113-05:00","updated_at":"2025-12-12T15:47:29.178955-05:00","closed_at":"2025-12-12T15:47:29.178955-05:00","dependencies":[{"issue_id":"qmd-vro","depends_on_id":"qmd-ama","type":"discovered-from","created_at":"2025-12-12T15:29:53.963641-05:00","created_by":"daemon"}]}
|
||||
{"id":"qmd-x19","title":"Update 'qmd add-context' for collection-scoped contexts","description":"Update add-context to work with collections:\n- qmd add-context \u003ccollection\u003e/\u003cpath\u003e \"context description\"\n- Support both virtual and filesystem paths\n- Update to use new path_contexts schema","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-12T15:29:38.142575-05:00","updated_at":"2025-12-12T15:53:00.525001-05:00","closed_at":"2025-12-12T15:53:00.525001-05:00"}
|
||||
|
||||
17
src/qmd.ts
17
src/qmd.ts
@ -435,17 +435,8 @@ function showStatus(): void {
|
||||
indexSize = stat;
|
||||
} catch {}
|
||||
|
||||
// Collections info
|
||||
const collections = db.prepare(`
|
||||
SELECT c.id, c.name, c.pwd, c.glob_pattern, c.created_at,
|
||||
COUNT(d.id) as doc_count,
|
||||
SUM(CASE WHEN d.active = 1 THEN 1 ELSE 0 END) as active_count,
|
||||
MAX(d.modified_at) as last_modified
|
||||
FROM collections c
|
||||
LEFT JOIN documents d ON d.collection = c.name
|
||||
GROUP BY c.id
|
||||
ORDER BY c.name
|
||||
`).all() as { id: number; name: string; pwd: string; glob_pattern: string; created_at: string; doc_count: number; active_count: number; last_modified: string | null }[];
|
||||
// Collections info (from YAML + database stats)
|
||||
const collections = listCollections(db);
|
||||
|
||||
// Overall stats
|
||||
const totalDocs = db.prepare(`SELECT COUNT(*) as count FROM documents WHERE active = 1`).get() as { count: number };
|
||||
@ -768,7 +759,7 @@ function contextRemove(pathArg: string): void {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const changes = deleteContext(db, coll.id, parsed.path);
|
||||
const changes = deleteContext(db, coll.name, parsed.path);
|
||||
|
||||
if (changes === 0) {
|
||||
console.error(`${c.yellow}No context found for: ${pathArg}${c.reset}`);
|
||||
@ -796,7 +787,7 @@ function contextRemove(pathArg: string): void {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const changes = deleteContext(db, detected.collectionId, detected.relativePath);
|
||||
const changes = deleteContext(db, detected.collectionName, detected.relativePath);
|
||||
|
||||
if (changes === 0) {
|
||||
console.error(`${c.yellow}No context found for: qmd://${detected.collectionName}/${detected.relativePath}${c.reset}`);
|
||||
|
||||
166
src/store.ts
166
src/store.ts
@ -217,6 +217,10 @@ function initializeDatabase(db: Database): void {
|
||||
return; // Migration will call initializeDatabase again
|
||||
}
|
||||
|
||||
// Drop legacy tables that are now managed in YAML
|
||||
db.exec(`DROP TABLE IF EXISTS path_contexts`);
|
||||
db.exec(`DROP TABLE IF EXISTS collections`);
|
||||
|
||||
// Content-addressable storage - the source of truth for document content
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS content (
|
||||
@ -226,20 +230,8 @@ function initializeDatabase(db: Database): void {
|
||||
)
|
||||
`);
|
||||
|
||||
// Collections table with name field
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS collections (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
pwd TEXT NOT NULL,
|
||||
glob_pattern TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
UNIQUE(pwd, glob_pattern)
|
||||
)
|
||||
`);
|
||||
|
||||
// Documents table - file system layer mapping virtual paths to content hashes
|
||||
// Collections are now managed in ~/.config/qmd/index.yml
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS documents (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
@ -259,20 +251,6 @@ function initializeDatabase(db: Database): void {
|
||||
db.exec(`CREATE INDEX IF NOT EXISTS idx_documents_hash ON documents(hash)`);
|
||||
db.exec(`CREATE INDEX IF NOT EXISTS idx_documents_path ON documents(path, active)`);
|
||||
|
||||
// Path-based context (collection-scoped, hierarchical)
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS path_contexts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
collection_id INTEGER NOT NULL,
|
||||
path_prefix TEXT NOT NULL,
|
||||
context TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
FOREIGN KEY (collection_id) REFERENCES collections(id) ON DELETE CASCADE,
|
||||
UNIQUE(collection_id, path_prefix)
|
||||
)
|
||||
`);
|
||||
db.exec(`CREATE INDEX IF NOT EXISTS idx_path_contexts_collection ON path_contexts(collection_id, path_prefix)`);
|
||||
|
||||
// Cache table for Ollama API calls
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS ollama_cache (
|
||||
@ -1026,25 +1004,12 @@ export function cleanupOrphanedVectors(db: Database): number {
|
||||
|
||||
/**
|
||||
* Remove duplicate collections, keeping the oldest one per (pwd, glob_pattern).
|
||||
* Also removes bogus "." glob pattern entries.
|
||||
* Returns the number of duplicate collections removed.
|
||||
* NOTE: This function is deprecated since collections are now managed in YAML.
|
||||
* Kept for backwards compatibility but returns 0.
|
||||
*/
|
||||
export function cleanupDuplicateCollections(db: Database): number {
|
||||
// Count duplicates before removal
|
||||
const beforeCount = (db.prepare(`SELECT COUNT(*) as c FROM collections`).get() as { c: number }).c;
|
||||
|
||||
// Remove duplicates keeping the oldest one
|
||||
db.exec(`
|
||||
DELETE FROM collections WHERE id NOT IN (
|
||||
SELECT MIN(id) FROM collections GROUP BY pwd, glob_pattern
|
||||
)
|
||||
`);
|
||||
|
||||
// Remove bogus "." glob pattern entries (from earlier bug)
|
||||
db.exec(`DELETE FROM collections WHERE glob_pattern = '.'`);
|
||||
|
||||
const afterCount = (db.prepare(`SELECT COUNT(*) as c FROM collections`).get() as { c: number }).c;
|
||||
return beforeCount - afterCount;
|
||||
// Collections are now managed in YAML, no cleanup needed
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1447,15 +1412,9 @@ export function insertContext(db: Database, collectionId: number, pathPrefix: st
|
||||
* Delete a context for a specific collection and path prefix.
|
||||
* Returns the number of contexts deleted.
|
||||
*/
|
||||
export function deleteContext(db: Database, collectionId: number, pathPrefix: string): number {
|
||||
// Get collection name from ID
|
||||
const coll = db.prepare(`SELECT name FROM collections WHERE id = ?`).get(collectionId) as { name: string } | null;
|
||||
if (!coll) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function deleteContext(db: Database, collectionName: string, pathPrefix: string): number {
|
||||
// Use collections.ts to remove context
|
||||
const success = collectionsRemoveContext(coll.name, pathPrefix);
|
||||
const success = collectionsRemoveContext(collectionName, pathPrefix);
|
||||
return success ? 1 : 0;
|
||||
}
|
||||
|
||||
@ -1901,11 +1860,11 @@ export function reciprocalRankFusion(
|
||||
// =============================================================================
|
||||
|
||||
type DbDocRow = {
|
||||
filepath: string;
|
||||
display_path: string;
|
||||
title: string;
|
||||
hash: string;
|
||||
collection: string;
|
||||
path: string;
|
||||
modified_at: string;
|
||||
body_length: number;
|
||||
body?: string;
|
||||
@ -1928,46 +1887,54 @@ export function findDocument(db: Database, filename: string, options: { includeB
|
||||
|
||||
const bodyCol = options.includeBody ? `, content.doc as body` : ``;
|
||||
|
||||
// Build computed columns for filepath and display_path
|
||||
// Build computed columns for display_path
|
||||
// Note: filepath is computed from YAML collections after query
|
||||
const selectCols = `
|
||||
c.pwd || '/' || d.path as filepath,
|
||||
'qmd://' || d.collection || '/' || d.path as display_path,
|
||||
d.title,
|
||||
d.hash,
|
||||
d.collection,
|
||||
d.path,
|
||||
d.modified_at,
|
||||
LENGTH(content.doc) as body_length
|
||||
${bodyCol}
|
||||
`;
|
||||
|
||||
// Try various match strategies - always join content for body_length
|
||||
// Try to match by virtual path first
|
||||
let doc = db.prepare(`
|
||||
SELECT ${selectCols}
|
||||
FROM documents d
|
||||
JOIN collections c ON c.name = d.collection
|
||||
JOIN content ON content.hash = d.hash
|
||||
WHERE c.pwd || '/' || d.path = ? AND d.active = 1
|
||||
WHERE 'qmd://' || d.collection || '/' || d.path = ? AND d.active = 1
|
||||
`).get(filepath) as DbDocRow | null;
|
||||
|
||||
// Try fuzzy match by virtual path
|
||||
if (!doc) {
|
||||
doc = db.prepare(`
|
||||
SELECT ${selectCols}
|
||||
FROM documents d
|
||||
JOIN collections c ON c.name = d.collection
|
||||
JOIN content ON content.hash = d.hash
|
||||
WHERE 'qmd://' || d.collection || '/' || d.path = ? AND d.active = 1
|
||||
`).get(filepath) as DbDocRow | null;
|
||||
WHERE 'qmd://' || d.collection || '/' || d.path LIKE ? AND d.active = 1
|
||||
LIMIT 1
|
||||
`).get(`%${filepath}`) as DbDocRow | null;
|
||||
}
|
||||
|
||||
if (!doc) {
|
||||
doc = db.prepare(`
|
||||
SELECT ${selectCols}
|
||||
FROM documents d
|
||||
JOIN collections c ON c.name = d.collection
|
||||
JOIN content ON content.hash = d.hash
|
||||
WHERE (c.pwd || '/' || d.path LIKE ? OR 'qmd://' || d.collection || '/' || d.path LIKE ?) AND d.active = 1
|
||||
LIMIT 1
|
||||
`).get(`%${filepath}`, `%${filepath}`) as DbDocRow | null;
|
||||
// Try to match by absolute path (requires looking up collection paths from YAML)
|
||||
if (!doc && !filepath.startsWith('qmd://')) {
|
||||
const collections = collectionsListCollections();
|
||||
for (const coll of collections) {
|
||||
const absPath = `${coll.path}/${filepath}`;
|
||||
const relativePath = absPath.startsWith(coll.path + '/') ? absPath.slice(coll.path.length + 1) : null;
|
||||
if (relativePath) {
|
||||
doc = db.prepare(`
|
||||
SELECT ${selectCols}
|
||||
FROM documents d
|
||||
JOIN content ON content.hash = d.hash
|
||||
WHERE d.collection = ? AND d.path = ? AND d.active = 1
|
||||
`).get(coll.name, relativePath) as DbDocRow | null;
|
||||
if (doc) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!doc) {
|
||||
@ -1975,10 +1942,13 @@ export function findDocument(db: Database, filename: string, options: { includeB
|
||||
return { error: "not_found", query: filename, similarFiles: similar };
|
||||
}
|
||||
|
||||
const context = getContextForFile(db, doc.filepath);
|
||||
// Compute absolute filepath from collection (in YAML) and relative path
|
||||
const coll = getCollection(doc.collection);
|
||||
const absoluteFilepath = coll ? `${coll.path}/${doc.path}` : doc.path;
|
||||
const context = getContextForFile(db, absoluteFilepath);
|
||||
|
||||
return {
|
||||
filepath: doc.filepath,
|
||||
filepath: absoluteFilepath,
|
||||
displayPath: doc.display_path,
|
||||
title: doc.title,
|
||||
context,
|
||||
@ -1996,13 +1966,37 @@ export function findDocument(db: Database, filename: string, options: { includeB
|
||||
*/
|
||||
export function getDocumentBody(db: Database, doc: DocumentResult | { filepath: string }, fromLine?: number, maxLines?: number): string | null {
|
||||
const filepath = 'filepath' in doc ? doc.filepath : doc.filepath;
|
||||
const row = db.prepare(`
|
||||
SELECT content.doc as body
|
||||
FROM documents d
|
||||
JOIN collections c ON c.name = d.collection
|
||||
JOIN content ON content.hash = d.hash
|
||||
WHERE c.pwd || '/' || d.path = ? AND d.active = 1
|
||||
`).get(filepath) as { body: string } | null;
|
||||
|
||||
// Try to resolve document by filepath (absolute or virtual)
|
||||
let row: { body: string } | null = null;
|
||||
|
||||
// Try virtual path first
|
||||
if (filepath.startsWith('qmd://')) {
|
||||
row = db.prepare(`
|
||||
SELECT content.doc as body
|
||||
FROM documents d
|
||||
JOIN content ON content.hash = d.hash
|
||||
WHERE 'qmd://' || d.collection || '/' || d.path = ? AND d.active = 1
|
||||
`).get(filepath) as { body: string } | null;
|
||||
}
|
||||
|
||||
// Try absolute path by looking up in YAML collections
|
||||
if (!row) {
|
||||
const collections = collectionsListCollections();
|
||||
for (const coll of collections) {
|
||||
if (filepath.startsWith(coll.path + '/')) {
|
||||
const relativePath = filepath.slice(coll.path.length + 1);
|
||||
row = db.prepare(`
|
||||
SELECT content.doc as body
|
||||
FROM documents d
|
||||
JOIN content ON content.hash = d.hash
|
||||
WHERE d.collection = ? AND d.path = ? AND d.active = 1
|
||||
`).get(coll.name, relativePath) as { body: string } | null;
|
||||
if (row) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!row) return null;
|
||||
|
||||
let body = row.body;
|
||||
@ -2059,11 +2053,11 @@ export function findDocuments(
|
||||
|
||||
const bodyCol = options.includeBody ? `, content.doc as body` : ``;
|
||||
const selectCols = `
|
||||
c.pwd || '/' || d.path as filepath,
|
||||
'qmd://' || d.collection || '/' || d.path as display_path,
|
||||
d.title,
|
||||
d.hash,
|
||||
d.collection,
|
||||
d.path,
|
||||
d.modified_at,
|
||||
LENGTH(content.doc) as body_length
|
||||
${bodyCol}
|
||||
@ -2078,7 +2072,6 @@ export function findDocuments(
|
||||
let doc = db.prepare(`
|
||||
SELECT ${selectCols}
|
||||
FROM documents d
|
||||
JOIN collections c ON c.name = d.collection
|
||||
JOIN content ON content.hash = d.hash
|
||||
WHERE 'qmd://' || d.collection || '/' || d.path = ? AND d.active = 1
|
||||
`).get(name) as DbDocRow | null;
|
||||
@ -2086,7 +2079,6 @@ export function findDocuments(
|
||||
doc = db.prepare(`
|
||||
SELECT ${selectCols}
|
||||
FROM documents d
|
||||
JOIN collections c ON c.name = d.collection
|
||||
JOIN content ON content.hash = d.hash
|
||||
WHERE 'qmd://' || d.collection || '/' || d.path LIKE ? AND d.active = 1
|
||||
LIMIT 1
|
||||
@ -2115,7 +2107,6 @@ export function findDocuments(
|
||||
fileRows = db.prepare(`
|
||||
SELECT ${selectCols}
|
||||
FROM documents d
|
||||
JOIN collections c ON c.name = d.collection
|
||||
JOIN content ON content.hash = d.hash
|
||||
WHERE 'qmd://' || d.collection || '/' || d.path IN (${placeholders}) AND d.active = 1
|
||||
`).all(...virtualPaths) as DbDocRow[];
|
||||
@ -2124,11 +2115,14 @@ export function findDocuments(
|
||||
const results: MultiGetResult[] = [];
|
||||
|
||||
for (const row of fileRows) {
|
||||
const context = getContextForFile(db, row.filepath);
|
||||
// Compute absolute filepath from collection
|
||||
const coll = getCollection(row.collection);
|
||||
const absoluteFilepath = coll ? `${coll.path}/${row.path}` : row.path;
|
||||
const context = getContextForFile(db, absoluteFilepath);
|
||||
|
||||
if (row.body_length > maxBytes) {
|
||||
results.push({
|
||||
doc: { filepath: row.filepath, displayPath: row.display_path },
|
||||
doc: { filepath: absoluteFilepath, displayPath: row.display_path },
|
||||
skipped: true,
|
||||
skipReason: `File too large (${Math.round(row.body_length / 1024)}KB > ${Math.round(maxBytes / 1024)}KB)`,
|
||||
});
|
||||
@ -2137,7 +2131,7 @@ export function findDocuments(
|
||||
|
||||
results.push({
|
||||
doc: {
|
||||
filepath: row.filepath,
|
||||
filepath: absoluteFilepath,
|
||||
displayPath: row.display_path,
|
||||
title: row.title || row.display_path.split('/').pop() || row.display_path,
|
||||
context,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user