Skip to content

Commit

Permalink
refoactor: drop path field frpm db
Browse files Browse the repository at this point in the history
  • Loading branch information
divyam234 committed Jun 7, 2024
1 parent b92f751 commit 94ef73d
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 59 deletions.
149 changes: 149 additions & 0 deletions internal/database/migrations/20240607113052_modify_functions.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
-- +goose Up
-- +goose StatementBegin
CREATE OR REPLACE FUNCTION teldrive.get_file_from_path(full_path text,u_id bigint)
RETURNS setof teldrive.files AS $$
DECLARE
target_id text;
begin

IF full_path = '/' then
RETURN QUERY select * from teldrive.files as root where root.parent_id = 'root';
END IF;

WITH RECURSIVE dir_hierarchy AS (
SELECT
root.id,
root.name,
root.parent_id,
0 AS depth,
'' as path
FROM
teldrive.files as root
WHERE
root.parent_id = 'root' AND root.user_id = u_id

UNION ALL

SELECT
f.id,
f.name,
f.parent_id,
dh.depth + 1 AS depth,
dh.path || '/' || f.name
FROM
teldrive.files f
JOIN
dir_hierarchy dh ON dh.id = f.parent_id
WHERE f.type = 'folder' AND f.user_id = u_id
)

SELECT id into target_id FROM dir_hierarchy dh
WHERE dh.path = full_path
ORDER BY dh.depth DESC
LIMIT 1;

RETURN QUERY select * from teldrive.files where id=target_id;

END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION teldrive.create_directories(u_id bigint, long_path text)
RETURNS SETOF teldrive.files AS $$
DECLARE
path_parts TEXT[];
current_directory_id TEXT;
new_directory_id TEXT;
directory_name TEXT;
path_so_far TEXT;
depth_dir INTEGER;
BEGIN
path_parts := string_to_array(regexp_replace(long_path, '^/+', ''), '/');
path_so_far := '';
depth_dir := 0;

SELECT id INTO current_directory_id FROM teldrive.files WHERE parent_id = 'root';

FOR directory_name IN SELECT unnest(path_parts) LOOP
depth_dir := depth_dir + 1;

SELECT id INTO new_directory_id
FROM teldrive.files
WHERE parent_id = current_directory_id
AND "name" = directory_name
AND "user_id" = u_id;

IF new_directory_id IS NULL THEN
INSERT INTO teldrive.files ("name", "type", mime_type, parent_id, "user_id", starred, "depth")
VALUES (directory_name, 'folder', 'drive/folder', current_directory_id, u_id, false, depth_dir)
RETURNING id INTO new_directory_id;
END IF;

current_directory_id := new_directory_id;
END LOOP;

RETURN QUERY SELECT * FROM teldrive.files WHERE id = current_directory_id;
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION teldrive.move_directory(src text, dest text, u_id bigint)
RETURNS void AS $$
DECLARE
src_parent TEXT;
src_base TEXT;
dest_parent TEXT;
dest_base TEXT;
dest_id text;
dest_parent_id text;
src_id text;
begin

select id into src_id from teldrive.get_file_from_path(src,u_id);

select id into dest_id from teldrive.get_file_from_path(dest,u_id);

IF src_id is NULL THEN
RAISE EXCEPTION 'source directory not found';
END IF;

IF dest_id is not NULL then
RAISE EXCEPTION 'destination directory exists';
END IF;

SELECT parent, base INTO src_parent,src_base FROM teldrive.split_path(src);

SELECT parent, base INTO dest_parent, dest_base FROM teldrive.split_path(dest);

IF src_parent != dest_parent then
select id into dest_id from teldrive.create_directories(u_id,dest);
UPDATE teldrive.files SET parent_id = dest_id WHERE parent_id = src_id;
delete from teldrive.files where id = src_id;
END IF;

IF src_base != dest_base and src_parent = dest_parent then
UPDATE teldrive.files SET name = dest_base WHERE id = src_id;
END IF;

END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION teldrive.move_items(file_ids text[], dest text, u_id bigint)
RETURNS void AS $$
declare
dest_id TEXT;
BEGIN

select id into dest_id from teldrive.get_file_from_path(dest,u_id);

IF dest_id is NULL then
select id into dest_id from teldrive.create_directories(u_id,dest);
END IF;

UPDATE teldrive.files
SET parent_id = dest_id
WHERE id = ANY(file_ids);
END;
$$ LANGUAGE plpgsql;

DROP INDEX IF EXISTS "path_idx";
ALTER TABLE "teldrive"."files" DROP COLUMN IF EXISTS "path";
-- +goose StatementEnd
1 change: 0 additions & 1 deletion pkg/mapper/mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ func ToFileOut(file models.File) *schemas.FileOut {
Type: file.Type,
MimeType: file.MimeType,
Category: file.Category,
Path: file.Path,
Encrypted: file.Encrypted,
Size: size,
Starred: file.Starred,
Expand Down
1 change: 0 additions & 1 deletion pkg/models/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ type File struct {
Name string `gorm:"type:text;not null"`
Type string `gorm:"type:text;not null"`
MimeType string `gorm:"type:text;not null"`
Path string `gorm:"type:text;index"`
Size *int64 `gorm:"type:bigint"`
Starred bool `gorm:"default:false"`
Depth *int `gorm:"type:integer"`
Expand Down
2 changes: 0 additions & 2 deletions pkg/schemas/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ type FileOut struct {
MimeType string `json:"mimeType"`
Category string `json:"category,omitempty"`
Encrypted bool `json:"encrypted"`
Path string `json:"path,omitempty"`
Size int64 `json:"size,omitempty"`
Starred bool `json:"starred"`
ParentID string `json:"parentId,omitempty"`
Expand All @@ -63,7 +62,6 @@ type FileOutFull struct {
type FileUpdate struct {
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
Path string `json:"path,omitempty"`
Starred *bool `json:"starred,omitempty"`
ParentID string `json:"parentId,omitempty"`
UpdatedAt time.Time `json:"updatedAt,omitempty"`
Expand Down
1 change: 0 additions & 1 deletion pkg/services/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ func (as *AuthService) LogIn(c *gin.Context, session *schemas.TgSession) (*schem
Name: "root",
Type: "folder",
MimeType: "drive/folder",
Path: "/",
Depth: utils.IntPointer(0),
UserID: session.UserID,
Status: "active",
Expand Down
96 changes: 45 additions & 51 deletions pkg/services/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,30 +48,31 @@ func NewFileService(db *gorm.DB, cnf *config.Config, worker *tgc.StreamWorker) *

func (fs *FileService) CreateFile(c *gin.Context, userId int64, fileIn *schemas.FileIn) (*schemas.FileOut, *types.AppError) {

var fileDB models.File
var (
fileDB models.File
parent *models.File
err error
)

fileIn.Path = strings.TrimSpace(fileIn.Path)

if fileIn.Path != "" {
pathId, err := fs.getPathId(fileIn.Path, userId)
if err != nil || pathId == "" {
if fileIn.Path != "" && fileIn.ParentID == "" {
parent, err = fs.getFileFromPath(fileIn.Path, userId)
if err != nil {
return nil, &types.AppError{Error: err, Code: http.StatusNotFound}
}
fileDB.ParentID = pathId
fileDB.ParentID = parent.Id
} else if fileIn.ParentID != "" {
fileDB.ParentID = fileIn.ParentID

} else {
return nil, &types.AppError{Error: fmt.Errorf("parent id or path is required"), Code: http.StatusBadRequest}
}

if fileIn.Type == "folder" {
fileDB.MimeType = "drive/folder"
var fullPath string
if fileIn.Path == "/" {
fullPath = "/" + fileIn.Name
} else {
fullPath = fileIn.Path + "/" + fileIn.Name
}
fileDB.Path = fullPath
fileDB.Depth = utils.IntPointer(len(strings.Split(fileIn.Path, "/")) - 1)
fileDB.Depth = utils.IntPointer(*parent.Depth + 1)
} else if fileIn.Type == "file" {
fileDB.Path = ""
channelId := fileIn.ChannelID
if fileIn.ChannelID == 0 {
var err error
Expand Down Expand Up @@ -110,29 +111,24 @@ func (fs *FileService) UpdateFile(id string, userId int64, update *schemas.FileU
files []models.File
chain *gorm.DB
)
if update.Type == "folder" && update.Name != "" {
chain = fs.db.Raw("select * from teldrive.update_folder(?, ?, ?)", id, update.Name, userId).Scan(&files)
} else {

updateDb := models.File{
Name: update.Name,
ParentID: update.ParentID,
UpdatedAt: update.UpdatedAt,
Path: update.Path,
Size: update.Size,
}

if update.Starred != nil {
updateDb.Starred = *update.Starred
}
updateDb := models.File{
Name: update.Name,
ParentID: update.ParentID,
UpdatedAt: update.UpdatedAt,
Size: update.Size,
}

if len(update.Parts) > 0 {
updateDb.Parts = datatypes.NewJSONSlice(update.Parts)
}
chain = fs.db.Model(&files).Clauses(clause.Returning{}).Where("id = ?", id).Updates(updateDb)
if update.Starred != nil {
updateDb.Starred = *update.Starred
}

cache.Delete(fmt.Sprintf("files:%s", id))
if len(update.Parts) > 0 {
updateDb.Parts = datatypes.NewJSONSlice(update.Parts)
}
chain = fs.db.Model(&files).Clauses(clause.Returning{}).Where("id = ?", id).Updates(updateDb)

cache.Delete(fmt.Sprintf("files:%s", id))

if chain.Error != nil {
return nil, &types.AppError{Error: chain.Error}
Expand Down Expand Up @@ -160,12 +156,12 @@ func (fs *FileService) GetFileByID(id string) (*schemas.FileOutFull, *types.AppE
func (fs *FileService) ListFiles(userId int64, fquery *schemas.FileQuery) (*schemas.FileResponse, *types.AppError) {

var (
pathId string
parent *models.File
err error
)

if fquery.Path != "" {
pathId, err = fs.getPathId(fquery.Path, userId)
parent, err = fs.getFileFromPath(fquery.Path, userId)
if err != nil {
return nil, &types.AppError{Error: err, Code: http.StatusNotFound}
}
Expand All @@ -176,16 +172,16 @@ func (fs *FileService) ListFiles(userId int64, fquery *schemas.FileQuery) (*sche

if fquery.Op == "list" {
filter := &models.File{UserID: userId, Status: "active"}
query.Order("type DESC").Order(getOrder(fquery)).Where("parent_id = ?", pathId).
query.Order("type DESC").Order(getOrder(fquery)).Where("parent_id = ?", parent.Id).
Model(filter).Where(&filter)

} else if fquery.Op == "find" {
if !fquery.DeepSearch && pathId != "" && (fquery.Name != "" || fquery.Query != "") {
query.Where("parent_id = ?", pathId)
if !fquery.DeepSearch && parent != nil && (fquery.Name != "" || fquery.Query != "") {
query.Where("parent_id = ?", parent.Id)
fquery.Path = ""
} else if fquery.DeepSearch && pathId != "" && fquery.Query != "" {
} else if fquery.DeepSearch && parent != nil && fquery.Query != "" {
query = fs.db.Clauses(exclause.With{Recursive: true, CTEs: []exclause.CTE{{Name: "subdirs",
Subquery: exclause.Subquery{DB: fs.db.Model(&models.File{Id: pathId}).Select("id", "parent_id").Clauses(exclause.NewUnion("ALL ?",
Subquery: exclause.Subquery{DB: fs.db.Model(&models.File{Id: parent.Id}).Select("id", "parent_id").Clauses(exclause.NewUnion("ALL ?",
fs.db.Table("teldrive.files as f").Select("f.id", "f.parent_id").
Joins("inner join subdirs ON f.parent_id = subdirs.id")))}}}}).Where("files.id in (select id from subdirs)")
fquery.Path = ""
Expand Down Expand Up @@ -247,7 +243,6 @@ func (fs *FileService) ListFiles(userId int64, fquery *schemas.FileQuery) (*sche
filter := &models.File{UserID: userId, Status: "active"}
filter.Name = fquery.Name
filter.ParentID = fquery.ParentID
filter.Path = fquery.Path
filter.Type = fquery.Type
if fquery.Starred != nil {
filter.Starred = *fquery.Starred
Expand All @@ -260,10 +255,6 @@ func (fs *FileService) ListFiles(userId int64, fquery *schemas.FileQuery) (*sche
setOrderFilter(query, fquery)
}

if fquery.Path == "" || fquery.DeepSearch {
query.Select("*,(select path from teldrive.files as ff where ff.id = files.parent_id) as parent_path")
}

files := []schemas.FileOut{}

query.Scan(&files)
Expand All @@ -281,16 +272,19 @@ func (fs *FileService) ListFiles(userId int64, fquery *schemas.FileQuery) (*sche
return res, nil
}

func (fs *FileService) getPathId(path string, userId int64) (string, error) {
func (fs *FileService) getFileFromPath(path string, userId int64) (*models.File, error) {

var file models.File
var res []models.File

if err := fs.db.Model(&models.File{}).Select("id").Where("path = ?", path).Where("user_id = ?", userId).
First(&file).Error; database.IsRecordNotFoundErr(err) {
return "", database.ErrNotFound
if err := fs.db.Raw("select * from teldrive.get_file_from_path(?, ?)", path, userId).
Scan(&res).Error; err != nil {
return nil, err

}
return file.Id, nil
if len(res) == 0 {
return nil, database.ErrNotFound
}
return &res[0], nil
}

func (fs *FileService) MakeDirectory(userId int64, payload *schemas.MkDir) (*schemas.FileOut, *types.AppError) {
Expand Down
3 changes: 0 additions & 3 deletions pkg/services/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ func (s *FileServiceSuite) SetupTest() {
Name: "root",
Type: "folder",
MimeType: "drive/folder",
Path: "/",
Depth: utils.IntPointer(0),
UserID: 123456,
Status: "active",
Expand Down Expand Up @@ -80,13 +79,11 @@ func (s *FileServiceSuite) Test_Update() {
s.NoError(err.Error)
data := &schemas.FileUpdate{
Name: "file3.jpeg",
Path: "/dwkd",
Type: "file",
}
r, err := s.srv.UpdateFile(res.Id, 123456, data, nil)
s.NoError(err.Error)
s.Equal(r.Name, data.Name)
s.Equal(r.Path, data.Path)
}

func (s *FileServiceSuite) Test_NoFound() {
Expand Down

0 comments on commit 94ef73d

Please sign in to comment.