-
Notifications
You must be signed in to change notification settings - Fork 0
โจ Feature: add content extractor #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a8554d9
97c34aa
1fb358d
abf077d
fe09783
f35e708
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -8,13 +8,13 @@ data class DataFileBulkCreateRequest( | |||||||||||||||||||||||||||||||||||||||||||||||||
| @field:Size(min = 1, message = "์ต์ ํ๋ ์ด์ ์ ๋ก๋ํด์ผ ํฉ๋๋ค") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @Valid | ||||||||||||||||||||||||||||||||||||||||||||||||||
| val items: List<DataFileCreateItem> | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| data class DataFileCreateItem( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @field:NotBlank(message = "title์ ๋น์ด์์ ์ ์์ต๋๋ค") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @field:Size(max = 100) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| val title: String, | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| data class DataFileCreateItem( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @field:NotBlank(message = "title์ ๋น์ด์์ ์ ์์ต๋๋ค") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @field:Size(max = 100) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| val title: String, | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| @field:Size(max = 10, message = "ํ๊ทธ๋ ์ต๋ 10๊ฐ๊น์ง ๊ฐ๋ฅํฉ๋๋ค") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| val tags: List<String> = emptyList() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| @field:Size(max = 10, message = "ํ๊ทธ๋ ์ต๋ 10๊ฐ๊น์ง ๊ฐ๋ฅํฉ๋๋ค") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| val tags: List<String> = emptyList() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+12
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐งน Nitpick (assertive) Optional: Strengthen validation on tags to prevent blank/oversized tag values Currently only the list size is validated. Consider enforcing per-tag constraints. Apply: data class DataFileCreateItem(
@field:NotBlank(message = "title์ ๋น์ด์์ ์ ์์ต๋๋ค")
@field:Size(max = 100)
val title: String,
- @field:Size(max = 10, message = "ํ๊ทธ๋ ์ต๋ 10๊ฐ๊น์ง ๊ฐ๋ฅํฉ๋๋ค")
- val tags: List<String> = emptyList()
+ @field:Size(max = 10, message = "ํ๊ทธ๋ ์ต๋ 10๊ฐ๊น์ง ๊ฐ๋ฅํฉ๋๋ค")
+ val tags: List<@NotBlank(message = "๋น ํ๊ทธ๋ ํ์ฉ๋์ง ์์ต๋๋ค") @Size(max = 30, message = "ํ๊ทธ๋ ์ต๋ 30์๊น์ง ๊ฐ๋ฅํฉ๋๋ค") String> = emptyList()
)๐ Committable suggestion
Suggested change
๐ค Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -18,7 +18,7 @@ data class DataFilePreviewResponse( | |||||||||||||
| companion object { | ||||||||||||||
| fun from(file: DataFile): DataFilePreviewResponse = | ||||||||||||||
| DataFilePreviewResponse( | ||||||||||||||
| id = requireNotNull(file.id) { "DataFile.id is null" }, | ||||||||||||||
| id = file.id, | ||||||||||||||
| sha256 = file.sha256, | ||||||||||||||
| ) | ||||||||||||||
|
Comment on lines
+21
to
23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Map id defensively; entity ids can be null before persistence. After switching entity id to nullable (recommended), avoid propagating a null or โ0โ id to API responses. Apply: - id = file.id,
+ id = requireNotNull(file.id) { "DataFile.id must be assigned" },
sha256 = file.sha256,๐ Committable suggestion
Suggested change
๐ค Prompt for AI Agents |
||||||||||||||
| } | ||||||||||||||
|
|
@@ -40,33 +40,33 @@ data class DataFileDetailResponseList( | |||||||||||||
| hasNext = hasNext, | ||||||||||||||
| ) | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| data class DataFileDetailResponse( | ||||||||||||||
| var id: Long?, | ||||||||||||||
| val title: String, | ||||||||||||||
| val type: String, | ||||||||||||||
| val lastModified: LocalDateTime, | ||||||||||||||
| val sizeMB: Double, | ||||||||||||||
| val tags: List<TagDTO>, | ||||||||||||||
| val sha256: String, | ||||||||||||||
| ) { | ||||||||||||||
| companion object { | ||||||||||||||
| fun from(file: DataFile, tags: List<TagDTO>): DataFileDetailResponse = | ||||||||||||||
| DataFileDetailResponse( | ||||||||||||||
| id = requireNotNull(file.id) { "DataFile.id is null" }, | ||||||||||||||
| title = file.title, | ||||||||||||||
| type = file.type, | ||||||||||||||
| lastModified = file.updatedAt, | ||||||||||||||
| sizeMB = file.sizeBytes.toMegaBytes(2), | ||||||||||||||
| tags = tags, | ||||||||||||||
| sha256 = file.sha256, | ||||||||||||||
| ) | ||||||||||||||
| data class DataFileDetailResponse( | ||||||||||||||
| val id: Long, | ||||||||||||||
| val title: String, | ||||||||||||||
| val type: String, | ||||||||||||||
| val lastModified: LocalDateTime, | ||||||||||||||
| val sizeMB: Double, | ||||||||||||||
| val tags: List<TagDTO>, | ||||||||||||||
| val sha256: String, | ||||||||||||||
| ) { | ||||||||||||||
| companion object { | ||||||||||||||
| fun from(file: DataFile, tags: List<TagDTO>): DataFileDetailResponse = | ||||||||||||||
| DataFileDetailResponse( | ||||||||||||||
| id = file.id, | ||||||||||||||
| title = file.title, | ||||||||||||||
| type = file.type, | ||||||||||||||
| lastModified = file.updatedAt, | ||||||||||||||
| sizeMB = file.sizeBytes.toMegaBytes(2), | ||||||||||||||
| tags = tags, | ||||||||||||||
| sha256 = file.sha256, | ||||||||||||||
| ) | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| data class TagDTO( | ||||||||||||||
| val id: Long?, | ||||||||||||||
| val id: Long, | ||||||||||||||
| val name: String, | ||||||||||||||
| ) { | ||||||||||||||
| companion object { | ||||||||||||||
|
|
||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -22,16 +22,17 @@ class DataFile( | |||||||||||||||||||||
| @Column(nullable = false, length = 64) | ||||||||||||||||||||||
| val sha256: String, | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @Column(nullable = false, length = 2048, name = "file_url") | ||||||||||||||||||||||
| val fileUrl: String, | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| @Column(nullable = false) | ||||||||||||||||||||||
| @Lob | ||||||||||||||||||||||
| val content: String, | ||||||||||||||||||||||
| ) : BaseEntity() { | ||||||||||||||||||||||
| @Id @GeneratedValue(strategy = GenerationType.IDENTITY) | ||||||||||||||||||||||
| @Column(name = "data_files_id") | ||||||||||||||||||||||
| val id: Long? = null, | ||||||||||||||||||||||
| ) : BaseEntity() { | ||||||||||||||||||||||
| val id: Long = 0 | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
|
Comment on lines
29
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generated ID cannot reliably be a non-null val initialized to 0; use nullable or mutable id. Hibernate needs to assign the identifier after insert. Apply: - @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
- @Column(name = "data_files_id")
- val id: Long = 0
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "data_files_id")
+ var id: Long? = nullFollow-up: update DTO mappers to require a non-null id at mapping time (see comments in DataFileResponseDTO.kt). ๐ Committable suggestion
Suggested change
๐ค Prompt for AI Agents |
||||||||||||||||||||||
| companion object { | ||||||||||||||||||||||
| fun from(title: String, type: String, sizeBytes : Long, sha256 : String, fileUrl: String): DataFile { | ||||||||||||||||||||||
| return DataFile(title, type, sizeBytes, sha256, fileUrl) | ||||||||||||||||||||||
| fun from(title: String, type: String, sizeBytes : Long, sha256 : String, content: String): DataFile { | ||||||||||||||||||||||
| return DataFile(title, type, sizeBytes, sha256, content) | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
Comment on lines
+34
to
36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐งน Nitpick (assertive) Factory method aligns with new model; consider basic invariants. Add lightweight checks to guard against invalid inputs, e.g., blank title/type, negative sizes. Example: - fun from(title: String, type: String, sizeBytes : Long, sha256 : String, content: String): DataFile {
- return DataFile(title, type, sizeBytes, sha256, content)
- }
+ fun from(title: String, type: String, sizeBytes: Long, sha256: String, content: String): DataFile {
+ require(title.isNotBlank()) { "title must not be blank" }
+ require(type.isNotBlank()) { "type must not be blank" }
+ require(sizeBytes >= 0) { "sizeBytes must be >= 0" }
+ require(sha256.length == 64) { "sha256 must be 64-char hex" }
+ return DataFile(title, type, sizeBytes, sha256, content)
+ }๐ Committable suggestion
Suggested change
๐ค Prompt for AI Agents |
||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -9,16 +9,15 @@ import simplerag.ragback.global.entity.BaseEntity | |||||||||||
| uniqueConstraints = [UniqueConstraint(columnNames = ["data_files_id", "tags_id"])] | ||||||||||||
| ) | ||||||||||||
| class DataFileTag( | ||||||||||||
|
|
||||||||||||
| @ManyToOne(fetch = FetchType.LAZY) | ||||||||||||
| @JoinColumn(name = "tags_id", nullable = false) | ||||||||||||
| @JoinColumn(name = "tags_id") | ||||||||||||
| var tag: Tag, | ||||||||||||
|
|
||||||||||||
|
Comment on lines
+13
to
15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FK nullability removed โ make the Tag relation non-nullable. This link table should not allow rows without a Tag. Removing Apply this to keep relational integrity: - @ManyToOne(fetch = FetchType.LAZY)
- @JoinColumn(name = "tags_id")
+ @ManyToOne(fetch = FetchType.LAZY, optional = false)
+ @JoinColumn(name = "tags_id", nullable = false)
var tag: Tag,๐ Committable suggestion
Suggested change
๐ค Prompt for AI Agents |
||||||||||||
| @ManyToOne(fetch = FetchType.LAZY) | ||||||||||||
| @JoinColumn(name = "data_files_id", nullable = false) | ||||||||||||
| var dataFile: DataFile, | ||||||||||||
|
|
||||||||||||
| @JoinColumn(name = "data_files_id") | ||||||||||||
| var dataFile: DataFile | ||||||||||||
| ) : BaseEntity() { | ||||||||||||
|
Comment on lines
+17
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FK nullability removed โ make the DataFile relation non-nullable. Same rationale as for Tag. The join row must always reference a DataFile. - @ManyToOne(fetch = FetchType.LAZY)
- @JoinColumn(name = "data_files_id")
- var dataFile: DataFile
+ @ManyToOne(fetch = FetchType.LAZY, optional = false)
+ @JoinColumn(name = "data_files_id", nullable = false)
+ var dataFile: DataFile
๐ค Prompt for AI Agents |
||||||||||||
| @Id @GeneratedValue(strategy = GenerationType.IDENTITY) | ||||||||||||
| @Column(name = "data_files_tags_id") | ||||||||||||
| val id: Long? = null, | ||||||||||||
| ) : BaseEntity() | ||||||||||||
| val id: Long = 0 | ||||||||||||
| } | ||||||||||||
|
Comment on lines
+22
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐ ๏ธ Refactor suggestion Primary key should be nullable for JPA; avoid sentinel Using - val id: Long = 0
+ var id: Long? = nullIf other entities in this PR shifted to non-null ๐ Committable suggestion
Suggested change
๐ค Prompt for AI Agents |
||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,8 +4,6 @@ import org.springframework.dao.DataIntegrityViolationException | |
| import org.springframework.data.domain.PageRequest | ||
| import org.springframework.stereotype.Service | ||
| import org.springframework.transaction.annotation.Transactional | ||
| import org.springframework.transaction.support.TransactionSynchronization | ||
| import org.springframework.transaction.support.TransactionSynchronizationManager | ||
| import org.springframework.web.multipart.MultipartFile | ||
| import simplerag.ragback.domain.document.dto.* | ||
| import simplerag.ragback.domain.document.entity.DataFile | ||
|
|
@@ -17,18 +15,18 @@ import simplerag.ragback.domain.document.repository.TagRepository | |
| import simplerag.ragback.global.error.CustomException | ||
| import simplerag.ragback.global.error.ErrorCode | ||
| import simplerag.ragback.global.error.FileException | ||
| import simplerag.ragback.global.util.s3.S3Type | ||
| import simplerag.ragback.global.util.s3.S3Util | ||
| import simplerag.ragback.global.util.converter.computeMetricsStreaming | ||
| import simplerag.ragback.global.util.converter.resolveContentType | ||
| import simplerag.ragback.global.util.extractor.ContentExtractorResolver | ||
| import java.util.* | ||
|
|
||
| @Service | ||
| @Transactional(readOnly = true) | ||
| class DataFileService( | ||
| private val dataFileRepository: DataFileRepository, | ||
| private val tagRepository: TagRepository, | ||
| private val dataFileTagRepository: DataFileTagRepository, | ||
| private val s3Util: S3Util, | ||
| private val contentExtractorResolver: ContentExtractorResolver | ||
| ) { | ||
|
|
||
| @Transactional | ||
|
|
@@ -40,9 +38,6 @@ class DataFileService( | |
| throw CustomException(ErrorCode.INVALID_INPUT) | ||
| } | ||
|
|
||
| val uploadedUrls = mutableListOf<String>() | ||
| registerRollbackCleanup(uploadedUrls) | ||
|
|
||
| val responses = files.mapIndexed { idx, file -> | ||
| val meta = req.items[idx] | ||
| val metrics = file.computeMetricsStreaming() | ||
|
|
@@ -54,25 +49,23 @@ class DataFileService( | |
| throw FileException(ErrorCode.ALREADY_FILE, sha256) | ||
| } | ||
|
|
||
| val fileUrl = s3Util.upload(file, S3Type.ORIGINAL_FILE) | ||
| uploadedUrls += fileUrl | ||
| val content = contentExtractorResolver.extractContent(file, type) | ||
|
|
||
| val dataFile = try { | ||
| dataFileRepository.save(DataFile.from(meta.title, type, sizeBytes, sha256, fileUrl)) | ||
| dataFileRepository.save(DataFile.from(meta.title, type, sizeBytes, sha256, content)) | ||
| } catch (ex: DataIntegrityViolationException) { | ||
|
Comment on lines
+52
to
56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐ ๏ธ Refactor suggestion Preserve root cause when mapping integrity violation to domain error You correctly guard for races using unique index + catch. However, the original exception is lost, hindering diagnostics and tripping static analysis (swallowed exception). - val dataFile = try {
- dataFileRepository.save(DataFile.from(meta.title, type, sizeBytes, sha256, content))
- } catch (ex: DataIntegrityViolationException) {
- throw FileException(ErrorCode.ALREADY_FILE, sha256)
- }
+ val dataFile = try {
+ dataFileRepository.save(DataFile.from(meta.title, type, sizeBytes, sha256, content))
+ } catch (ex: DataIntegrityViolationException) {
+ // keep cause for observability; preserves stack and satisfies static analysis
+ throw FileException(ErrorCode.ALREADY_FILE, sha256).also { it.initCause(ex) }
+ }If throw FileException(ErrorCode.ALREADY_FILE, sha256, ex)๐งฐ Tools๐ช detekt (1.23.8)[warning] 56-56: The caught exception is swallowed. The original exception could be lost. (detekt.exceptions.SwallowedException) ๐ค Prompt for AI Agents |
||
| throw FileException(ErrorCode.ALREADY_FILE, sha256) | ||
| } | ||
|
|
||
| val tags = getOrCreateTags(meta.tags) | ||
| attachTagsIfMissing(dataFile, tags) | ||
|
|
||
| DataFilePreviewResponse.from(dataFile) | ||
| return@mapIndexed DataFilePreviewResponse.from(dataFile) | ||
| } | ||
|
|
||
| return DataFilePreviewResponseList(responses) | ||
| } | ||
|
|
||
| @Transactional(readOnly = true) | ||
| fun getDataFiles( | ||
| cursor: Long, | ||
| take: Int | ||
|
|
@@ -82,7 +75,7 @@ class DataFileService( | |
| val allLinks = dataFileTagRepository.findAllByDataFileIn(files.content) | ||
| val tagsByFileId: Map<Long, List<TagDTO>> = | ||
| allLinks.groupBy( | ||
| keySelector = { requireNotNull(it.dataFile.id) { "DataFile.id is null" } } | ||
| { it.dataFile.id } | ||
| ).mapValues { (_, links) -> TagDTO.from(links) } | ||
|
|
||
| val nextCursor = files.content.lastOrNull()?.id | ||
|
|
@@ -92,28 +85,17 @@ class DataFileService( | |
|
|
||
| @Transactional | ||
| fun deleteFile(dataFilesId: Long) { | ||
| val dataFile = dataFileRepository.findDataFileById(dataFilesId) ?: throw FileException( | ||
| ErrorCode.NOT_FOUND, | ||
| dataFilesId.toString() | ||
| ) | ||
| val dataFile = dataFileRepository.findDataFileById(dataFilesId) | ||
| ?: throw FileException( | ||
| ErrorCode.NOT_FOUND, | ||
| dataFilesId.toString() | ||
| ) | ||
|
|
||
| dataFileTagRepository.deleteAllByDataFile(dataFile) | ||
|
|
||
| dataFileRepository.delete(dataFile) | ||
| } | ||
|
|
||
| private fun registerRollbackCleanup(uploadedUrls: MutableList<String>) { | ||
| if (TransactionSynchronizationManager.isSynchronizationActive()) { | ||
| TransactionSynchronizationManager.registerSynchronization(object : TransactionSynchronization { | ||
| override fun afterCompletion(status: Int) { | ||
| if (status == TransactionSynchronization.STATUS_ROLLED_BACK) { | ||
| uploadedUrls.forEach { runCatching { s3Util.deleteByUrl(it) } } | ||
| } | ||
| } | ||
| }) | ||
| } | ||
| } | ||
|
|
||
|
|
||
| private fun getOrCreateTags(names: List<String>): List<Tag> { | ||
| val normalized = names | ||
|
|
@@ -145,14 +127,14 @@ class DataFileService( | |
|
|
||
|
|
||
| private fun attachTagsIfMissing(dataFile: DataFile, tags: List<Tag>) { | ||
| val fileId = dataFile.id ?: return | ||
| tags.forEach { tag -> | ||
| val tagId = tag.id ?: return@forEach | ||
| val exists = dataFileTagRepository.existsByDataFileIdAndTagId(fileId, tagId) | ||
| if (!exists) { | ||
| dataFileTagRepository.save(DataFileTag(tag = tag, dataFile = dataFile)) | ||
| } | ||
| val temp = tags.mapNotNull { tag -> | ||
| val exists = dataFileTagRepository.existsByDataFileIdAndTagId(dataFile.id, tag.id) | ||
|
|
||
| if (exists) return@mapNotNull null | ||
|
|
||
| return@mapNotNull DataFileTag(tag = tag, dataFile = dataFile) | ||
| } | ||
| } | ||
|
|
||
| dataFileTagRepository.saveAll(temp) | ||
| } | ||
|
Comment on lines
+130
to
+139
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐งน Nitpick (assertive) Reduce N+1 existence checks when attaching tags Current code performs one - private fun attachTagsIfMissing(dataFile: DataFile, tags: List<Tag>) {
- val temp = tags.mapNotNull { tag ->
- val exists = dataFileTagRepository.existsByDataFileIdAndTagId(dataFile.id, tag.id)
-
- if (exists) return@mapNotNull null
-
- return@mapNotNull DataFileTag(tag = tag, dataFile = dataFile)
- }
-
- dataFileTagRepository.saveAll(temp)
- }
+ private fun attachTagsIfMissing(dataFile: DataFile, tags: List<Tag>) {
+ if (tags.isEmpty()) return
+ // Fetch once
+ val existingLinks = dataFileTagRepository.findAllByDataFileIdAndTagIdIn(
+ dataFile.id,
+ tags.map { it.id }
+ )
+ val existingTagIds = existingLinks.map { it.tag.id }.toHashSet()
+ val toCreate = tags
+ .asSequence()
+ .filter { it.id !in existingTagIds }
+ .map { DataFileTag(tag = it, dataFile = dataFile) }
+ .toList()
+ if (toCreate.isNotEmpty()) dataFileTagRepository.saveAll(toCreate)
+ }Add repository method (outside this hunk) if it doesnโt exist: interface DataFileTagRepository {
fun findAllByDataFileIdAndTagIdIn(dataFileId: Long, tagIds: List<Long>): List<DataFileTag>
}๐ค Prompt for AI Agents |
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -18,7 +18,7 @@ data class IndexPreviewResponseList( | |||||||||||
| } | ||||||||||||
|
|
||||||||||||
| data class IndexPreviewResponse( | ||||||||||||
| var indexId: Long?, | ||||||||||||
| var indexId: Long, | ||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐งน Nitpick (assertive) Make
-data class IndexPreviewResponse(
- var indexId: Long,
+data class IndexPreviewResponse(
+ val indexId: Long,๐ Committable suggestion
Suggested change
๐ค Prompt for AI Agents |
||||||||||||
| val snapshotName: String, | ||||||||||||
| ) { | ||||||||||||
| companion object { | ||||||||||||
|
|
@@ -32,7 +32,7 @@ data class IndexPreviewResponse( | |||||||||||
| } | ||||||||||||
|
|
||||||||||||
| data class IndexDetailResponse( | ||||||||||||
| var indexId: Long?, | ||||||||||||
| val indexId: Long, | ||||||||||||
| val snapshotName: String, | ||||||||||||
| val chunkingSize: Int, | ||||||||||||
| val overlapSize: Int, | ||||||||||||
|
|
||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,15 @@ | ||||||||||||||||||
| package simplerag.ragback.domain.index.embed | ||||||||||||||||||
|
|
||||||||||||||||||
| import org.springframework.context.annotation.Primary | ||||||||||||||||||
| import org.springframework.context.annotation.Profile | ||||||||||||||||||
| import org.springframework.stereotype.Component | ||||||||||||||||||
|
|
||||||||||||||||||
| @Component | ||||||||||||||||||
| @Primary | ||||||||||||||||||
| @Profile("test") | ||||||||||||||||||
| class FakeEmbder: Embedder { | ||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐ก Verification agent ๐งฉ Analysis chainFix class name typo and follow Kotlin spacing: The misspelling will confuse readers and may affect bean naming. Also add a space before -@Profile("test")
-class FakeEmbder: Embedder {
+@Profile("test")
+class FakeEmbedder : Embedder {๐ Script executed: #!/bin/bash
# Find all occurrences to update references after rename.
rg -nP '\bFakeEmbder\b|FakeEmbedder' -C2Length of output: 529 Action: Rename class and file to fix typo and update formatting To align with Kotlin naming conventions and prevent confusion (including Spring bean naming), please update the class and its file as follows: โข File to update:
Proposed diff: @@ -9,7 +9,7 @@
@Profile("test")
-class FakeEmbder: Embedder {
+class FakeEmbedder : Embedder {
override val dim: Int = 1536
override fun embed(text: String): FloatArray {
// ...๐ Committable suggestion
Suggested change
๐ค Prompt for AI Agents |
||||||||||||||||||
| override val dim: Int = 1536 | ||||||||||||||||||
| override fun embed(text: String): FloatArray { | ||||||||||||||||||
| return FloatArray(1536) { 0.0f } | ||||||||||||||||||
| } | ||||||||||||||||||
|
Comment on lines
+12
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐งน Nitpick (assertive) Avoid magic numbers; use the declared dimension. Tie the zero vector length to override val dim: Int = 1536
override fun embed(text: String): FloatArray {
- return FloatArray(1536) { 0.0f }
+ return FloatArray(dim) { 0.0f }
}๐ Committable suggestion
Suggested change
๐ค Prompt for AI Agents |
||||||||||||||||||
| } | ||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -40,11 +40,10 @@ class Index( | |||||||||||||||||||||
|
|
||||||||||||||||||||||
| @OneToMany(cascade = [CascadeType.ALL], orphanRemoval = true, mappedBy = "index") | ||||||||||||||||||||||
| val chunkEmbeddings: MutableList<ChunkEmbedding> = mutableListOf(), | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| ) : BaseEntity() { | ||||||||||||||||||||||
|
Comment on lines
41
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐งน Nitpick (assertive) Optional: Helper method to manage the bidirectional association Add a convenience method to keep Example (outside the shown range): fun addChunkEmbedding(e: ChunkEmbedding) {
chunkEmbeddings.add(e)
if (e.index !== this) {
// if ChunkEmbedding.index is mutable, set it here; otherwise add a factory to create with this index
}
}๐ค Prompt for AI Agents |
||||||||||||||||||||||
| @Id @GeneratedValue(strategy = GenerationType.IDENTITY) | ||||||||||||||||||||||
| @Column(name = "indexes_id") | ||||||||||||||||||||||
| var id: Long? = null, | ||||||||||||||||||||||
| ) : BaseEntity() { | ||||||||||||||||||||||
| val id: Long = 0 | ||||||||||||||||||||||
|
Comment on lines
+43
to
+46
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Blocking: Non-null id=0 under @GeneratedValue โ will cause repository.save() to merge Same issue as other entities. Revert to nullable id or implement Persistable. Apply this diff: ) : BaseEntity() {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "indexes_id")
- val id: Long = 0
+ var id: Long? = null๐ Committable suggestion
Suggested change
๐ค Prompt for AI Agents |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| companion object { | ||||||||||||||||||||||
| fun toIndex(createRequest: IndexCreateRequest): Index { | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
๐งน Nitpick (assertive)
Avoid version drift; centralize pgvector version and deduplicate test dependency.
Declare the version once and reuse it for both main and test scopes. Also, you typically donโt need
testImplementationifimplementationalready pulls it transitively for tests.Apply:
๐ค Prompt for AI Agents