migrate from github
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
package document_repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/XingfenD/yoresee_doc/internal/model"
|
||||
"github.com/XingfenD/yoresee_doc/pkg/key"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DocumentGetSubtreeOperation struct {
|
||||
repo *DocumentRepository
|
||||
rootParentID int64
|
||||
knowledgeID *int64
|
||||
depth *int
|
||||
|
||||
directoryOnly bool
|
||||
|
||||
tx *gorm.DB
|
||||
}
|
||||
|
||||
func (r *DocumentRepository) GetSubtree(rootParentID int64) *DocumentGetSubtreeOperation {
|
||||
return &DocumentGetSubtreeOperation{
|
||||
repo: r,
|
||||
rootParentID: rootParentID,
|
||||
}
|
||||
}
|
||||
|
||||
func (op *DocumentGetSubtreeOperation) WithTx(tx *gorm.DB) *DocumentGetSubtreeOperation {
|
||||
op.tx = tx
|
||||
return op
|
||||
}
|
||||
|
||||
func (op *DocumentGetSubtreeOperation) WithKnowledgeID(knowledgeID *int64) *DocumentGetSubtreeOperation {
|
||||
op.knowledgeID = knowledgeID
|
||||
return op
|
||||
}
|
||||
|
||||
func (op *DocumentGetSubtreeOperation) WithDepth(depth *int) *DocumentGetSubtreeOperation {
|
||||
op.depth = depth
|
||||
return op
|
||||
}
|
||||
|
||||
func (op *DocumentGetSubtreeOperation) WithDirectoryOnly(with bool) *DocumentGetSubtreeOperation {
|
||||
op.directoryOnly = with
|
||||
return op
|
||||
}
|
||||
|
||||
func (op *DocumentGetSubtreeOperation) Exec(ctx context.Context) ([]*model.Document, error) {
|
||||
db := op.repo.db
|
||||
if op.tx != nil {
|
||||
db = op.tx
|
||||
}
|
||||
|
||||
var documents []*model.Document
|
||||
|
||||
if op.depth != nil && *op.depth == 0 {
|
||||
return documents, nil
|
||||
}
|
||||
|
||||
type pathDepth struct {
|
||||
Path string
|
||||
Depth int
|
||||
}
|
||||
var root pathDepth
|
||||
err := db.Model(&model.Document{}).
|
||||
Select("path, depth").
|
||||
Where("id = ?", op.rootParentID).
|
||||
Take(&root).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return documents, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// in-transaction query should bypass cache to avoid stale reads
|
||||
if op.tx != nil || op.repo.redis == nil {
|
||||
return op.queryWithRoot(db, root.Path, root.Depth)
|
||||
}
|
||||
|
||||
version, err := op.repo.getSubtreeVersion(ctx, root.Path)
|
||||
if err == nil {
|
||||
cacheKey := key.KeyDocSubtree(root.Path, version, op.depth)
|
||||
if cachedIDs, ok, err := getCachedSubtreeIDs(ctx, cacheKey); err == nil && ok {
|
||||
return op.repo.fetchDocumentsByIDs(cachedIDs)
|
||||
}
|
||||
|
||||
val, err, _ := subtreeCacheSF.Do(cacheKey, func() (interface{}, error) {
|
||||
dbDocs, err := op.queryWithRoot(db, root.Path, root.Depth)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ids := make([]int64, 0, len(dbDocs))
|
||||
for _, doc := range dbDocs {
|
||||
ids = append(ids, doc.ID)
|
||||
}
|
||||
setCachedSubtreeIDs(ctx, cacheKey, ids)
|
||||
return dbDocs, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if typed, ok := val.([]*model.Document); ok {
|
||||
return typed, nil
|
||||
}
|
||||
}
|
||||
|
||||
return op.queryWithRoot(db, root.Path, root.Depth)
|
||||
}
|
||||
|
||||
func (op *DocumentGetSubtreeOperation) queryWithRoot(db *gorm.DB, rootPath string, rootDepth int) ([]*model.Document, error) {
|
||||
var documents []*model.Document
|
||||
|
||||
query := `
|
||||
SELECT *
|
||||
FROM document_metas
|
||||
WHERE deleted_at IS NULL
|
||||
AND id <> ?
|
||||
AND path <@ ?
|
||||
`
|
||||
if op.directoryOnly {
|
||||
query = `
|
||||
SELECT id, external_id, title, parent_id, type
|
||||
FROM document_metas
|
||||
WHERE deleted_at IS NULL
|
||||
AND id <> ?
|
||||
AND path <@ ?
|
||||
`
|
||||
}
|
||||
args := []interface{}{op.rootParentID, rootPath}
|
||||
if op.knowledgeID != nil {
|
||||
query += " AND knowledge_id = ?"
|
||||
args = append(args, *op.knowledgeID)
|
||||
}
|
||||
if op.depth != nil {
|
||||
maxDepth := rootDepth + *op.depth
|
||||
query += " AND depth <= ?"
|
||||
args = append(args, maxDepth)
|
||||
}
|
||||
query += " ORDER BY depth, created_at"
|
||||
|
||||
if err := db.Raw(query, args...).Find(&documents).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return documents, nil
|
||||
}
|
||||
Reference in New Issue
Block a user