From 5ba9daa5a6c65e8066399e75e7a80c0a02af77ce Mon Sep 17 00:00:00 2001 From: Elie Gambache Date: Wed, 28 Oct 2026 02:22:24 +0200 Subject: [PATCH] feat(dao): load a line's cross-references and sources with their books getReferencesForLines returns the lines the cross-reference links of some lines reach: REFERENCE and MESORAT_HASHAS in both directions (they are stored once, unoriented), EIN_MISHPAT forward only (its reverse is the SOURCE view). getSourcesForLines returns the SOURCE view in the same shape and order (declared bases first, then base books, then catalog). Each LineReference carries the reached line, the line of the request it starts from, and its book's title, category and catalog rank: all the reader needs to group the places by book and filter them by category, in one query instead of one per book. Signed-off-by: Elie Gambache --- .../dao/repository/SeforimRepository.kt | 65 +++++++++++++++++++ .../seforimlibrary/db/LinkQueries.sq | 34 ++++++++++ 2 files changed, 99 insertions(+) diff --git a/dao/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/dao/repository/SeforimRepository.kt b/dao/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/dao/repository/SeforimRepository.kt index 75136b5e..0fe7fc08 100644 --- a/dao/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/dao/repository/SeforimRepository.kt +++ b/dao/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/dao/repository/SeforimRepository.kt @@ -1664,6 +1664,60 @@ class SeforimRepository(databasePath: String, private val driver: SqlDriver) : L forward + inverse } + /** + * The lines that the cross-reference links of [lineIds] point to: REFERENCE and MESORAT_HASHAS in + * both directions (these links are unoriented and stored once), EIN_MISHPAT forward only (its + * reverse is the SOURCE view). A line is returned once, however many links reach it; the lines of + * [lineIds] themselves are left out. + */ + suspend fun getReferencesForLines(lineIds: Collection): List = + withContext(Dispatchers.IO) { + if (lineIds.isEmpty()) return@withContext emptyList() + database.linkQueriesQueries.selectReferencesByLineIds(lineIds, lineIds) { + _, connectionType, fromLineId, lineId, bookId, lineIndex, heRef, content, bookTitle, categoryId, bookOrderIndex -> + lineReference(connectionType, fromLineId, lineId, bookId, lineIndex, heRef, content, bookTitle, categoryId, bookOrderIndex) + }.executeAsList() + .filter { it.line.id !in lineIds } + .distinctBy { it.line.id } + } + + /** + * The lines that [lineIds] comment on (the SOURCE view), as [getReferencesForLines] returns its + * lines, in the SOURCE view's order. A line is returned once, however many links reach it. + */ + suspend fun getSourcesForLines(lineIds: Collection): List = + withContext(Dispatchers.IO) { + if (lineIds.isEmpty()) return@withContext emptyList() + database.linkQueriesQueries.selectSourcesByLineIds(lineIds) { + _, _, fromLineId, lineId, bookId, lineIndex, heRef, content, bookTitle, categoryId, bookOrderIndex -> + lineReference( + ConnectionType.SOURCE.name, fromLineId, lineId, bookId, lineIndex, heRef, content, bookTitle, categoryId, + bookOrderIndex, + ) + }.executeAsList() + .distinctBy { it.line.id } + } + + private fun lineReference( + connectionType: String, + fromLineId: Long, + lineId: Long, + bookId: Long, + lineIndex: Long, + heRef: String?, + content: String, + bookTitle: String, + categoryId: Long, + bookOrderIndex: Long, + ) = LineReference( + connectionType = ConnectionType.fromString(connectionType), + fromLineId = fromLineId, + line = Line(id = lineId, bookId = bookId, lineIndex = lineIndex.toInt(), content = content, heRef = heRef), + bookTitle = bookTitle, + categoryId = categoryId, + bookOrderIndex = bookOrderIndex.toInt(), + ) + /** * Lightweight variant for prefetch/navigation use cases; omits target text content. * When [includeSources] is false (default), only forward links are returned — callers @@ -2984,3 +3038,14 @@ data class CommentarySummary( val link: Link, val targetBookTitle: String ) + +/** A line a cross-reference link reaches, with what its book's grouping needs. */ +data class LineReference( + val connectionType: ConnectionType, + /** The line of the request this link starts from. */ + val fromLineId: Long, + val line: Line, + val bookTitle: String, + val categoryId: Long, + val bookOrderIndex: Int, +) diff --git a/dao/src/commonMain/sqldelight/io/github/kdroidfilter/seforimlibrary/db/LinkQueries.sq b/dao/src/commonMain/sqldelight/io/github/kdroidfilter/seforimlibrary/db/LinkQueries.sq index ee7bde23..fc19b2e7 100644 --- a/dao/src/commonMain/sqldelight/io/github/kdroidfilter/seforimlibrary/db/LinkQueries.sq +++ b/dao/src/commonMain/sqldelight/io/github/kdroidfilter/seforimlibrary/db/LinkQueries.sq @@ -343,3 +343,37 @@ WHERE l.targetBookId = ? AND l.sourceBookId != l.targetBookId GROUP BY l.sourceBookId, b.title, a.name ORDER BY MAX(l.isDeclaredBase) DESC, b.isBaseBook DESC, b.orderIndex, b.title; + +-- The cross-reference links of lines: the line on the other side of each link, with its book. +-- REFERENCE and MESORAT_HASHAS are unoriented (stored once): both directions. EIN_MISHPAT runs from +-- a line to the codes that rule on it: forward only, its reverse being the SOURCE view. +selectReferencesByLineIds: +SELECT l.id AS linkId, ct.name AS connectionType, l.sourceLineId AS fromLineId, ol.id AS lineId, ol.bookId, ol.lineIndex, ol.heRef, ol.content, + b.title AS bookTitle, b.categoryId, b.orderIndex AS bookOrderIndex +FROM link l +JOIN connection_type ct ON l.connectionTypeId = ct.id +JOIN line ol ON ol.id = l.targetLineId +JOIN book b ON b.id = ol.bookId +WHERE ct.name IN ('REFERENCE', 'MESORAT_HASHAS', 'EIN_MISHPAT') AND l.sourceLineId IN ? +UNION ALL +SELECT l.id AS linkId, ct.name AS connectionType, l.targetLineId AS fromLineId, ol.id AS lineId, ol.bookId, ol.lineIndex, ol.heRef, ol.content, + b.title AS bookTitle, b.categoryId, b.orderIndex AS bookOrderIndex +FROM link l +JOIN connection_type ct ON l.connectionTypeId = ct.id +JOIN line ol ON ol.id = l.sourceLineId +JOIN book b ON b.id = ol.bookId +WHERE ct.name IN ('REFERENCE', 'MESORAT_HASHAS') AND l.targetLineId IN ?; + +-- The SOURCE view of lines in the shape of selectReferencesByLineIds: the lines these lines comment +-- on, with their book, in the SOURCE view's order (declared bases first, then base books, then catalog). +selectSourcesByLineIds: +SELECT l.id AS linkId, ct.name AS connectionType, l.targetLineId AS fromLineId, ol.id AS lineId, ol.bookId, ol.lineIndex, ol.heRef, ol.content, + b.title AS bookTitle, b.categoryId, b.orderIndex AS bookOrderIndex +FROM link l +JOIN connection_type ct ON l.connectionTypeId = ct.id +JOIN line ol ON ol.id = l.sourceLineId +JOIN book b ON b.id = ol.bookId +WHERE l.targetLineId IN ? + AND ct.name IN ('COMMENTARY','SUPER_COMMENTARY','TARGUM','MIDRASH','PARSHANUT','DIBUR_HAMATCHIL','EIN_MISHPAT') + AND l.sourceBookId != l.targetBookId +ORDER BY l.isDeclaredBase DESC, b.isBaseBook DESC, b.orderIndex, ol.lineIndex;