diff --git a/core/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/core/models/Book.kt b/core/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/core/models/Book.kt index a9575f0..4bf7f10 100644 --- a/core/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/core/models/Book.kt +++ b/core/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/core/models/Book.kt @@ -9,6 +9,8 @@ import kotlinx.serialization.Serializable * @property id The unique identifier of the book * @property categoryId The identifier of the category this book belongs to * @property title The title of the book + * @property heRef A stable Hebrew reference identifier for the book, used for consistent identification + * across database regenerations (e.g., "בראשית", "רש״י על בראשית") * @property sourceId The identifier of the source this book originates from * @property authors The list of authors of this book * @property topics The list of topics associated with this book @@ -28,6 +30,7 @@ data class Book( val categoryId: Long, val sourceId: Long, val title: String, + val heRef: String? = null, val authors: List = emptyList(), val topics: List = emptyList(), val pubPlaces: List = emptyList(), diff --git a/dao/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/dao/extensions/ModelExtensions.kt b/dao/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/dao/extensions/ModelExtensions.kt index 7c621f4..7447db1 100644 --- a/dao/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/dao/extensions/ModelExtensions.kt +++ b/dao/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/dao/extensions/ModelExtensions.kt @@ -78,6 +78,7 @@ fun io.github.kdroidfilter.seforimlibrary.db.Book.toModel(json: Json, authors: L categoryId = categoryId, sourceId = sourceId, title = title, + heRef = heRef, authors = authors, topics = emptyList(), pubPlaces = pubPlaces, 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 06727d5..dd0111f 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 @@ -641,6 +641,19 @@ class SeforimRepository(databasePath: String, private val driver: SqlDriver) { return@withContext bookData.toModel(json, authors, pubPlaces, pubDates).copy(topics = topics) } + /** + * Retrieves a book by its stable Hebrew reference identifier (heRef). + * Returns null if no book with the given heRef exists. + */ + suspend fun getBookByHeRef(heRef: String): Book? = withContext(Dispatchers.IO) { + val bookData = database.bookQueriesQueries.selectByHeRef(heRef).executeAsOneOrNull() ?: return@withContext null + val authors = getBookAuthors(bookData.id) + val topics = getBookTopics(bookData.id) + val pubPlaces = getBookPubPlaces(bookData.id) + val pubDates = getBookPubDates(bookData.id) + return@withContext bookData.toModel(json, authors, pubPlaces, pubDates).copy(topics = topics) + } + /** * Retrieves a book by approximate title (exact, normalized, or LIKE). */ @@ -852,6 +865,7 @@ class SeforimRepository(databasePath: String, private val driver: SqlDriver) { categoryId = book.categoryId, sourceId = book.sourceId, title = book.title, + heRef = book.heRef, heShortDesc = book.heShortDesc, notesContent = book.notesContent, orderIndex = book.order.toLong(), @@ -909,6 +923,7 @@ class SeforimRepository(databasePath: String, private val driver: SqlDriver) { categoryId = book.categoryId, sourceId = book.sourceId, title = book.title, + heRef = book.heRef, heShortDesc = book.heShortDesc, notesContent = book.notesContent, orderIndex = book.order.toLong(), diff --git a/dao/src/commonMain/sqldelight/io/github/kdroidfilter/seforimlibrary/db/BookQueries.sq b/dao/src/commonMain/sqldelight/io/github/kdroidfilter/seforimlibrary/db/BookQueries.sq index 3048c2f..cc6bd9f 100644 --- a/dao/src/commonMain/sqldelight/io/github/kdroidfilter/seforimlibrary/db/BookQueries.sq +++ b/dao/src/commonMain/sqldelight/io/github/kdroidfilter/seforimlibrary/db/BookQueries.sq @@ -40,12 +40,15 @@ selectBaseIds: SELECT id FROM book WHERE isBaseBook = 1 ORDER BY orderIndex, title; insert: -INSERT INTO book (categoryId, sourceId, title, heShortDesc, notesContent, orderIndex, totalLines, isBaseBook, hasSourceConnection, hasAltStructures, hasTeamim, hasNekudot) -VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); +INSERT INTO book (categoryId, sourceId, title, heRef, heShortDesc, notesContent, orderIndex, totalLines, isBaseBook, hasSourceConnection, hasAltStructures, hasTeamim, hasNekudot) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); insertWithId: -INSERT INTO book (id, categoryId, sourceId, title, heShortDesc, notesContent, orderIndex, totalLines, isBaseBook, hasSourceConnection, hasAltStructures, hasTeamim, hasNekudot) -VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); +INSERT INTO book (id, categoryId, sourceId, title, heRef, heShortDesc, notesContent, orderIndex, totalLines, isBaseBook, hasSourceConnection, hasAltStructures, hasTeamim, hasNekudot) +VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + +selectByHeRef: +SELECT * FROM book WHERE heRef = ? LIMIT 1; updateTotalLines: UPDATE book SET totalLines = ? WHERE id = ?; diff --git a/dao/src/commonMain/sqldelight/io/github/kdroidfilter/seforimlibrary/db/Database.sq b/dao/src/commonMain/sqldelight/io/github/kdroidfilter/seforimlibrary/db/Database.sq index 33cd012..45bc822 100644 --- a/dao/src/commonMain/sqldelight/io/github/kdroidfilter/seforimlibrary/db/Database.sq +++ b/dao/src/commonMain/sqldelight/io/github/kdroidfilter/seforimlibrary/db/Database.sq @@ -69,6 +69,7 @@ CREATE TABLE IF NOT EXISTS book ( categoryId INTEGER NOT NULL, sourceId INTEGER NOT NULL, title TEXT NOT NULL, + heRef TEXT, heShortDesc TEXT, -- Optional raw notes attached to the base book (when a companion file 'הערות על ' exists) notesContent TEXT, @@ -91,6 +92,7 @@ CREATE INDEX IF NOT EXISTS idx_book_category ON book(categoryId); CREATE INDEX IF NOT EXISTS idx_book_title ON book(title); CREATE INDEX IF NOT EXISTS idx_book_order ON book(orderIndex); CREATE INDEX IF NOT EXISTS idx_book_source ON book(sourceId); +CREATE INDEX IF NOT EXISTS idx_book_heref ON book(heRef); -- Book-publication place junction table CREATE TABLE IF NOT EXISTS book_pub_place ( diff --git a/generator/otzariasqlite/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/otzariasqlite/Generator.kt b/generator/otzariasqlite/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/otzariasqlite/Generator.kt index 60d01a8..54530ae 100644 --- a/generator/otzariasqlite/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/otzariasqlite/Generator.kt +++ b/generator/otzariasqlite/src/commonMain/kotlin/io/github/kdroidfilter/seforimlibrary/otzariasqlite/Generator.kt @@ -728,6 +728,7 @@ class DatabaseGenerator( categoryId = categoryId, sourceId = sourceId, title = title, + heRef = title, authors = authors, pubPlaces = pubPlaces, pubDates = pubDates, diff --git a/generator/sefariasqlite/src/jvmMain/kotlin/io/github/kdroidfilter/seforimlibrary/sefariasqlite/SefariaDirectImporter.kt b/generator/sefariasqlite/src/jvmMain/kotlin/io/github/kdroidfilter/seforimlibrary/sefariasqlite/SefariaDirectImporter.kt index 266d681..785f142 100644 --- a/generator/sefariasqlite/src/jvmMain/kotlin/io/github/kdroidfilter/seforimlibrary/sefariasqlite/SefariaDirectImporter.kt +++ b/generator/sefariasqlite/src/jvmMain/kotlin/io/github/kdroidfilter/seforimlibrary/sefariasqlite/SefariaDirectImporter.kt @@ -174,6 +174,7 @@ class SefariaDirectImporter( categoryId = catId, sourceId = sourceId, title = payload.heTitle, + heRef = payload.heTitle, authors = payload.authors.map { Author(name = it) }, pubPlaces = emptyList(), pubDates = payload.pubDates,